
正文
JavaScript 作用域链其实很简单
提示:扫一扫查出行【扫一扫了解最新限行尾号】
复制提示
概念
作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。 其本质就是一个指向变量对象的指针列表 。在js中,当某个函数被调用时,会创建一个执行环境(execution context)及相应的作用域链。然后使用 arguments和其他命名参数的值来初始化函数的活动对象(activation object) 。在作用域链中,外部函数的活动对象始终位于第二位,外部函数的外部函数的活动对象位于第三位,......直至作为作用域终点的全局执行环境。
(1) arguments和命名参数 可以去看另一篇博客 JavaScript 神奇的参数。
(2) 活动对象: 在一个函数对象被调用的时候,会创建一个活动对象。该函数的命名参数和arguments参数数组会被添加为该活动对象的属性,同时该函数体内显示声明的变量和函数,也会添加为该活动对象的属性(因为JS的提前声明机制,所以并没有立即赋值,值为undefined)。
在函数执行过程中,为了读取和写入变量的值,就需要在作用域中查找变量。看下面的例子:
function compare(value1,value2) {
if (value1 < value2){
return -1;
}else if(value1 > value2){
return 1;
}else{
return 0;
}
}
var result = compare(5,10);
以上代码先定义了compare()函数,然后在全局作用域中调用了它。当调用compare()时,会创建一个包含arguments、value1、value2的活动对象。全局执行环境的变量对象(包括result和compare)在compare() 执行环境的作用域中处于第二位。下图展示了包括上述关系的compare()函数执行时的作用域链。
从上图中可以看出compare的 执行环境内部有一个属性指向当前作用域链 ,而 compare()的活动对象 就保存在作用域链的最前面(第一位)也就是下标为0的位置。 全局执行环境的变量对象 则处于第二位,也就是下标为1的位置。
过程大致为:在创建compare()函数时,会创建一个预先 包含全局变量对象 的作用域链,这个 作用域链被保存在内部的[[Scope]]属性中 。当调用compare()函数时,会为函数创建一个执行环境,然后 通过复制函数的[[Scope]]属性中的对象构建起执行环境的作用域链 。此后,又有一个 活动对象被创建并推入执行环境作用域链的前端 。对于这个例子中compare()函数的执行环境而言,其作用域中包含两个变量对象: 本地活动对象 和 全局变量对象 。从这里就可以看出, 作用域链的本质就是一个指向量的指针列表 ,它只引用但不实际包含变量对象。






