重读犀牛-变量作用域札记

这是我参与 11 月更文挑战的第 23 天,活动详情查看:2021 最后一次更文挑战

变量作用域

变量值初始值时 undefined. 没有块级作用域(block scope)。

函数作用域(function scope):变量在声明它们的函数体以及这个函数体嵌套的任意函数体内都是有定义的。

声明提前(hoisting)

函数里声明的所有变量(但不涉及赋值)都被“提前”至函数体的顶部. 变量声明放在函数体顶部。

var scope = "global";
function f() {
 console.log(scope);  // 输出"undefined",而不是"global"
 var scope = "local"; // 变量在这里赋初始值,但变量本身在函数体内任何地方均是有定义的
 console.log(scope);  // 输出"local"
}
//等价于
var scope = "global";
function f() {
 var scope;
 console.log(scope);  
 scope = "local";  
 console.log(scope);  
}
复制代码

全局变量(global variable)

当声明一个JavaScript全局变量时,实际上是定义了全局对象的一个属性。

  • 当使用var声明一个变量时,创建的这个属性是不可配置的,无法通过delete运算符删除。
  • 在非严格模式并给一个未声明的变量赋值的话,JavaScript会自动创建一个全局变量,是可配置属性,可以删除。

作用域链(scope chain)

JavaScript是基于词法作用域(lexical scoping)的语言:通过阅读包含变量定义在内的数行源码就能知道变量的作用域。

当JavaScript需要查找变量x的值的过程称做“变量解析”(variable resolution

在最顶层代码中(也就是不包含在任何函数定义内的代码),作用域链由一个全局对象组成。

  • 在不包含嵌套的函数体内,作用域链上有两个对象,
  • 第一个是定义函数参数和局部变量的对象,
  • 第二个是全局对象。
  • 在一个嵌套的函数体内,作用域链上至少有三个对象。

当定义一个函数时,它实际上保存一个作用域链。当调用这个函数时,它创建一个新的对象来存储它的局部变量,并将这个对象添加至保存的那个作用域链上,同时创建一个新的更长的表示函数调用作用域的“链”。

对于嵌套函数来讲,事情变得更加有趣,每次调用外部函数时,内部函数又会重新定义一遍。因为每次调用外部函数的时候,作用域链都是不同的。内部函数在每次定义的时候都有微妙的差别——在每次调用外部函数时,内部函数的代码都是相同的,而且关联这段代码的作用域链也不相同。

猜你喜欢

转载自juejin.im/post/7033690948999577630