JavaScript 函数创建作用域链的过程

97 阅读1分钟

作用域链本质上是一个指向变量对象的指针列表

关键词

  • 执行环境
  • 全局变量对象和活动对象
  • 作用域链

函数的创建

函数在被创建时,会创建作用域链,它预先包含外层函数的活动对象,外层函数的外层函数的活动对象,...,全局变量对象。这样说比较抽象,事实上它预先包含为外层对象的作用域链,它被保存在函数内部的 [[Scope]] 属性中。

[[Scope]] 属性不能被开发者访问

用一个例子来说明:

function fnParent(){
    //其它代码
    ...
    const fnChild = function(){
        //其它代码
        ...
    }
}

在这个例子中,fnChild()被创建时, [[Scope]] 属性(作用域链)继承了fnParent()的作用域链。

函数的调用

函数调用时会创建函数的执行环境,然后将函数内部的 [[Scope]] 属性复制给函数执行环境作用域链。在此之后,会将 arguments对象 和函数调用时传递的实参初始化给函数的活动对象,并将函数的活动对象推入函数的执行环境作用域链的前端。

将上面的例子稍微加工:

function fnParent(){
    //其它代码
    ...
    x = 100
    const fnChild = function(){
        //其它代码
        ...
        return x++
    }
    return fnChild
}
fnParent()()  //101

在这个例子中,调用了fnParent()中的fnChild(),fnChild()的活动对象没有x,它将会沿着作用域链一层一层向后端搜索,直至找到fnParent()活动对象中的x。

下面这张图展示了上述函数中的作用域链的关系:

全局变量对象.png