作用域链
作用域链是对象的集合,在代码的上下文里,他们提供给标识符进行查找的。
这个规则也很简单,类似于原型链:如果一个变量在它自己的作用域(自己的变量/激活对象)未找到的话,它会继续找它的
父变量对象,依次类推。
对于上下文,标识符有: 变量的名称,函数声明,形参,等等。当一个函数查找它代码的标识符,这个标识符不是本地的变量(
或本地函数,或一个形参),这个变量就就称为自由变量。那么查找这些自由变量就会使用到作用域链。
通常情况下,作用域链是所有的父变量对象的集合,加上(在这个作用域链最前面的)这个函数自身的变量/激活对象。然而,这个
链域可能包含了其他的对象,比如,对象动态的添加到这个作用域链这个上下文执行期间,通过 with--对象,或捕获异常对象。
当去查找某个标识符时,作用域链会从当前的激活对象开始查找,并(如果在自身的激活对象里没找到的话)继续向上查找,重复
下去,同原型链一样。
var x = 10; (function foo(){ var y = 20; (function bar(){ var z = 30; /* x,y 是自由变量, 在bar的作用域链中, 他们会被查到在接下 来的对象(继bar的激 活对象) */ consloe.log( x + y + z ); })(); })()
我们将会使用内部属性__parent__来连接作用域对象,这个内部属性会引用到这个作用域链的下个对象。另外一种现实可能是通过数组。
通过__parent__概念,我有下面的图片关于来展现上面的代码(此外,变量对象是存放在函数的[[Scope]]属性的。
在代码执行时,作用域链可以被 with 语句和 catch 语句赋值为对象。尽管这些是简单对象,他们同样有属性(和原型链)。这
会导致这个作用域链查找有两个分支:(1)先看看一个作用域链,(2)在每一个作用域链上—就会进入到这个域链的原型链(
如果这个链域有原型对象)。
Object.prototype.x = 10; var w = 20; var y = 30; console.log( x ); // 10; (function foo(){ // "foo" local variables var w = 40; var x = 100; with({z:50}){ coonsole.log( w, x, y, z ); //40,10,30,50 } console.log( x, w ); // 100, 40 console.log( window.w ); //20 })();
我们有如下结构图(在我们访问__parent__域链,会先访问 __proto__链。
注意到,不是所有的全局对象实现继承自 Object.prototype。出现这种结果可能是在 SpiderMonkey 引擎里测试的。
直到所有的父变量对象存在,没什么特别的从内部函数获取父数据——我们遍历作用域链去找需要的变量。然而,正如我们上面提到的,
在一个上下文结束,它的所有状态和它自己也被销毁了。同时,一个内部函数可能会从父函数里返回。通常,这个返回的函数会被再次
激活由另一个上下文。带有这个激活对象是否会把这个带有一些自由变量的上下文确实是“销毁”了吗?在普遍的理论上,一个概念有助于
解决这个问题称为闭包,在ECMAScript里这个是直接与作用域链相关的。