《JavaScript高级程序设计》总结(五)—— 作用域链

410 阅读2分钟

先来复习一下,执行上下文的构成

执行上下文

  • 变量对象(Variable object,VO)
  • 作用域链(Scope chain)
  • this的指向

之前说了变量对象,现在来说下另外两个

作用域链(Scope chain)

通俗地讲,当声明一个函数时,局部作用域一级一级向上包起来,就是作用域链。

我们从函数定义到执行一步一步来说明

当函数定义的时候

当函数被定义的时候,会读取函数内部的一个属性,[[scope]]属性来保存就会保存所有父变量对象到其中,可以理解 [[scope]] 就是所有父变量对象的层级链

function a(){
    function b(){
        
    }
}

分析一下,当函数创建时,各自的[[scope]]为

a.[[scope] = [
   globalContext.VO
]

b.[[scope]] = [
    aContext.AO,
    globalContext.VO
];

当函数激活的时候

当函数激活的时候,创建VO/AO。并将其加入作用域链的第一位,作用域链(scope)到现在就创建完毕了

写个例子结合函数的上下文,变量对象等知识说明下作用域链

var global = '全局变量'
function abs(){
    a = 1
    console.log(a)
}
abs()

1.函数abs被创建,将作用域链保存到[[scope]]中

abs.[[scope]] = [
     globalContext.VO
]

2.abs函数开始执行,此时创建abs函数的执行上下文,并入栈

ECstack = [
    absContext
    globalContext
]

3.abs做正式执行前的准备工作,将[[scope]]属性作为作用域链,此时的abs执行上下文

absContext = {
     Scope: abs.[[scope]],
}

4.初始化变量对象,VO/AO

absContext = {
    AO: {
        arguments: {
            length: 0
        },
        a: undefined
    },
    Scope:abs.[[scope]]
}

5.将活动对象AO加到作用域链的顶端

absContext = {
    AO: {
        arguments: {
            length: 0
        },
        a: undefined
    },
    Scope:[AO,abs.[[scope]]]
}

至此,准备工作完成

6.随着函数的进行,AO开始进行赋值工作

checkscopeContext = {
    AO: {
        arguments: {
            length: 0
        },
        a: 1
    },
    Scope: [AO, [[Scope]]]
}

7.在作用域链中找到a的值并打印

8.abs执行完毕,abs的执行上下文栈弹出

ECstack = [
    globalContext
]