深入理解JavaScript执行过程:作用域和作用域链,执行上下文,预编译等

这篇博客已经酝酿很久了,但是仍然感觉自己对这方面的内容还没达理解融汇的地步,加油啊!这篇博客是对我另一篇博客的更详尽的说明补充,下文有提到。

JS中的作用域ES6之前只有两种,全局作用域(Global Scope),局部作用域(Local Scope又称函数作用域),作用域顾名思义就是变量能够起作用的区域,全局作用域定义的变量在全局范围内都有用。在函数2作用域内,局部作用域定义的变量的优先级大于前者,并且只在这个函数范围内有用。至于作用域链是由作用域构建的。

执行期上下文(execution context)是函数执行前被创建的,里面有三个属性,

1,变量对象VO,variable object

2,作用域链,Scope Chain

3,this,

我们以函数执行为线索来探究他们到底有什么联系,首先看代码

    var name = 'Joe';
    function call(){
        var name = 'Joi';
        console.log(name);//'Joi'
    }
    call();

为什么不是 'Joe' 呢?

一,首先 call 函数被创建,保存作用域链到函数内部属性[[ Scope ]],这一步其实是继承全局的作用域,

    call.[[scope]] = [
        globalContext.VO//全局的执行上下文
    ]

二,开始着手执行函数,创建执行上下文execution object,不是真的执行,毕竟作用域中啥也没。

    callExecutionContext{
        AO
        scope chain
        this   
    }

三,函数并不立即执行,需要一定准备工作,初始化执行上下文   execution object

1,,复制函数属性[[ scope ]]来创建作用域链,

    callExecutionContext{
            AO
            scope chain:[
                call.[[scope]
            ];
            this   
        }

2,用arguments来创建活动对象,并且初始化,具体过程请参考我的博客《JS预编译》,大概过程就是加入形参,函数声明,变量声明等属性,

    callExecutionContext{
            AO:{
                name:undefined;
                ……
            }
             scope chain:[
                call.[[scope]
            ];
            this   
        }

3,将上一步创建的活动对象压入作用域链顶端

    callExecutionContext{
            AO:{
                name:undefined;
                ……
            }
             scope chain:[
                AO
                call.[[scope]
            ];
            this   
        }

四,准备工作完成开始执行函数,随着函数执行,作用域中的变量也随之被赋值

    callExecutionContext{
            AO:{
                name:Joi;
                ……
            }
             scope chain:[
                AO
                call.[[scope]
            ];
            this   
        }

五,函数执行完毕,函数的执行上下文销毁,(是否完全销毁看情况)

可以看出,其实作用域链和作用域是难解难分的,它可以理解为执行上下文的集合,当例子中要访问name属性时,去作用域中寻找相应的属性,如果没有就往下,在globalExecutionContext中寻找。以此类推。而整个过程我们可以叫做预编译,他为函数的执行做了准备工作。

AO(activation object)和VO(variable object)其实是一个东西,只不过是不同时期的叫法而已,当上一级函数的作用域中的AO随着下一级函数的AO压入作用域时,才会变成VO,才可以访问各种属性,换句话说,只有下一级函数继承上一级函数作用域完成时,上一级函数的活动对象才会变成VO。

参考资料,红宝书,冴羽(超级厉害)的《深入JS系列》,你不知道的JS,等。

 

 

 

 

 

 

 

 

 

猜你喜欢

转载自blog.csdn.net/qq_41995398/article/details/103844415