- 作用域链是 JavaScript 提供的一套解决标识符的访问机制:JavaScript 规定每一个作用域都有一个与之相关联的作用域链。
- 作用域链用来在函数执行时求出标识符的值。
- 在对标识符进行求值的过程中:该链中包含多个对象,就会从【链首的对象】开始,然后依次查找后面的对象,直到在某个对象中找到与标识符名称相同的属性。如果在作用域链的顶端(全局对象)中仍然没有找到同名的属性,则返回 undefined 的属性值。
(在每个对象中进行属性查找的时候,还会使用该对象的原型域链。在一个执行上下文,与其关联的作用域链只会被 with 语句和 catch 子句影响。)
通过多层嵌套函数设计一个作用域链,在最内层函数中可以逐级访问外层函数的私有变量。
var a = 1; //全局变量
(function () {
var b = 2; //第1层局部变量
(function () {
var c = 3; //第2层局部变量
(function () {
var d = 4; //第3层局部变量
console.log(a + b + c + d); //返回10
}) () //直接调用函数
}) () //直接调用函数
}) () //直接调用函数
- 作用域链创建
①函数创建
函数的作用域在函数定义的时候就已经确定。
每个函数都有一个内部属性 [[scope]],当函数创建的时候,[[scope]] 保存所有父变量对象的引用,[[scope]] 就是一个层级链。
注意,[[scope]] 并不代表完整的作用域链。
function f1() {
function f2() {
//...
}
}
f1.[[scope]] = [
globalContext.VO // globalContext 表示全局上下文,VO 表示变量对象
];
f2.[[scope]] = [
f1Context.AO, // f1Context 表示函数 f1 的上下文,AO 表示活动对象。
globalContext.VO // globalContext 表示全局上下文,VO 表示变量对象
];
②函数激活
当函数激活时,进入函数上下文,创建 VO/AO 后,就会将【活动对象】添加到作用域链的前端。
这时如果命名执行上下文的作用域链为 Scope,则可以表示为:
Scope = [AO].concat([[scope]]);