变量、作用域与内存
嗨,大家好。我是 lovefat ,一个不值一提的爬虫工程师。在这个内卷的时代,对于爬虫工程师 Js 的要求也越来越高。所以我也决定要开始恶补 JavaScript 了。虽然一直不愿意开始,但是万事开头难,希望这个系列能够一直坚持下去。Ps:这其实算是一个读书笔记,所以这个系列是干的不能再干的干货了,书的链接在这里 JavaScript高级程序设计第4版, 我这里是有电子版的,关注公众号私信我就可以获取
原始值与引用值
包含类型
-
原始值
undefined
,null
,boolean
,number
,string
,Symbol
-
引用值
本质都是对象
区别
区别 | 原始值 | 引用值 |
---|---|---|
创建方式 | 原始类型只能使用原始字面量形式。但是如果是使用 new 关键字,则会创建的 Object 对象 | |
复制 | 两者独立,重新申请内存空间 | 复制引用值(指针) |
传递参数 | 传值,不影响函数外部值 | 同样是传值,可以影响到外部对象,但是不能修改 |
确定类型 |
typeof (不包含 null ,实际是对象),引用值类型都是返回 Object
|
instanceof |
实例解释部分
-
创建方式
let name1 = "lovefat"; let name2 = new String("lovefat"); name1.age = 27; name2.age = 26; // new 方式创建,本质上是一个对象,这个后续还会讲到 console.log(name1, name1.age); // lovefat 27 console.log(name2, name2.age); // lovefat 26
-
传递参数
function setName(obj1, obj2) { obj1.name = "lovefat"; // 此时 obj2 存储的地址已经被修改,所以修改 name 也不会影响到原来的值 obj2 = new Object(); obj2.name = "lovefat"; } var obj1 = {}, obj2 = {}; setName(obj1, obj2); console.log(obj1.name, obj2.name); // lovefat undefined // 可证 传递的是值 而不是引用
执行上下文与作用域
作用域链
代码正在执行的上下文的变量始终位于作用域链的最前端。作用域链中的下一个变量对象来自包含上 下文,再下一个对象来自再下一个包含上下文。以此类推直至全局上下文;全局上下文的变量对象始终 是作用域链的最后一个变量对象。
作用域链此处讲解的比较简单,可以按照局部变量,全局变量来理解,之后比较复杂的作用域链,在细细研究
作用域链增强
这是两种特殊情况,作用域链的范围会被扩大
-
try/catch
语句的catch
块创建一个新的变量对象,包含要抛出的错误类型
-
with
语句function setUrl(){ let query = '?name=lovefat'; with(location){ console.log(href); // 因为我在浏览器打开了百度,返回就是百度网址 let url = href + query; } return url; // undefined 限制在块级作用域中 } setUrl()
变量声明
对比四种定义方式的异同
-
var
💡
var
变量会自动添加到最近的上下文(ps:如果不加声明就初始化,那么会自动添加到全局上下文)function sumNum(num1, num2) { sum = num1 + num2; // sum 添加到全局作用域 return sum; } sumNum(2, 4); console.log(sum); // 6
💡
var 声明会被拿到函数或全局作用域的顶部,位于作用域中所有代码之前。这个现象叫作“提升” (hoisting)
console.log(name); // ReferenceError console.log(name); var name = 'lovefat'; // undefined
-
let
块级作用域:
if
while
function
甚至是单独的块都是它的作用域{ let a = 1; console.log(a); } console.log(a); // ReferenceError
let 特别适合循环中迭代变量,避免var的变量泄露
for (var a = 1; a < 2; a++) { } for (let b = 1; b < 2; b++) { } console.log(a); // 2 // var 在之后 a 也可以访问到 console.log(b); // ReferenceError
-
const
声明周期内不能再重新赋值,其他都跟
let
类似如果想让整个对象都不能修改,可以使用 Object.freeze(),这样再给属性赋值时虽然不会报错, 但会静默失败
-
标识符查找
var color = 'blue'; function getColor() { let color = 'red'; { let color = 'green'; return color; } } // 块作用域内找到,就不会再沿着作用域链继续查找 console.log(getColor()); // 'green'