深入谈谈作用域链

383 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

1.函数执前

函数被定义时,就会创建函数的作用域 执行前的预编译会创建一个独一无二的AO对象,该对象中存有该函数中定义的变量和函数, 例如下列函数A的AO对象

function A(){
    var a = 4
}

AO对象创建,将A函数中定义的变量名为AO对象的属性名,值为AO对象对应属性的值(这里涉及预编译,简单介绍下)

AO:{
    a: 4;
}//A的AO对象

2.函数执行时

函数每执行一次就会创建一个AO对象 咱们不妨假设为开始有一个函数,定义时创建作用域然后预编译创建了AO对象A 当函数执行时函数内部也会有其他函数被定义然后产生作用域创建AO对象,假设为B 依次下去会有AO对象C,D...

 function A() {
    var a1 = 1

    function B() {
        var b = 2

        function C() {
            var c = 3

            function D() {
                var D = 4
            }
        }
    }
}

A{B{C{D}}} 作用域链就是这些AO对象的集合形成的一个链式结构如下

graph TD
D-->C--> B-->A

3. 函数执行后

最新被创建AO对象的在作用域链的顶端,最先被执行, 能访问之前创建AO对象函数的作用域,函数被执行完就会被销毁,然后依次下去 所以作用域链中较早创建AO对象的函数不能访问之后创建AO对象函数的作用域 本例来说D最新创建能访问之前的A,B,C的作用域当A执行完被销毁后就变成

graph TD
 C--> B-->A

D后面创建AO对象的作用域C,B,A已经找不到D的作用域了

 function A() {
    var a = 1

    function B() {
        var b = 2
        console.log(a)
        console.log(b) //3.B只能能访问A和自己函数中定义的变量
        function C() {
            var c = 3
            console.log(b)
            console.log(c)
            console.log(a) // //2.C只能能访问A,B和自己函数中定义的变量
            function D() {
                var D = 4
                console.log(b)
                console.log(c)
                console.log(a) //1.D能访问A,B,C和自己函数中定义的变量
            }
        }
    }
}

[[scope]]

而这样的作用域链就储存在函数的属性[[scope]](作用域)中,是不可访问的

总结

当函数执行的时候,会创建一个称为执行期上下文的内部对象(ao对象) 所以多次调用一个函数会导致创建多个执行期上下文,当函数执行完毕,它所产生的执行期上下文会被销毁。 执行期上下文对象的集合呈链式连接储存在函数属性[[scope]](作用域中)中,这就是作用域链。