继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

javascript 执行上下文系列总结

POPMUISE
关注TA
已关注
手记 273
粉丝 80
获赞 423

我在文章《javascript 执行上下文》中介绍了 javascript 代码在执行时,会相应地创建对应执行上下文并将其入栈出栈的过程。

每个执行上下文会包含三个重要属性,分别是变量对象(Variable Object,VO)作用域链(Scope Chain)this 指向

而我在文章《javascript 变量对象》《javascript 作用域链》《javascript this 指向》中详细地描述了在代码执行过程中,随着执行上下文的创建和执行,这三个重要属性的变化过程,接下来我就一个例子结合前面四篇文章,详细地说明执行上下文的具体处理过程。

假设有一个 javascript 文件中包含如下代码

function fn1() {    var a = 1;    function fn2(b) {        var c=3
    }
    
    fn2(2)
}

fn1();

我们依旧可以很容易地知道,上述代码在执行过程中,执行上下文栈的变化过程如下

/*伪代码*/// 代码执行时最先进入全局环境,全局上下文被创建并入栈ECStack.push(globalContext);// fn1 被调用,fn1 函数上下文被创建并入栈ECStack.push(<fn1> functionContext);// fn1 中调用 fn2,fn2 函数上下文被创建并入栈ECStack.push(<fn2> functionContext);// fn2 执行完毕,fn2 函数上下文出栈ECStack.pop();// fn1 执行完毕,fn1 函数上下文出栈ECStack.pop();// 代码执行完毕,全局上下文出栈ECStack.pop();

我们已经知道,执行上下文在创建阶段,会分别生成变量对象建立作用域链确定 this 指向。那么我们接下来就按照上述代码的流程,详细说明各个执行上下文中这三个重要属性的情况。

首先进入全局环境,全局上下文被创建并入栈

全局上下文被创建时,其执行上下文如下

globalContext={
    VO:globalObj
    Scope:[globalContext.VO]    this:globalContext.VO
}
接着 fn1 被调用,fn1 函数上下文被创建并入栈

这里需要说明的是,在 fn1 函数上下文被创建之前,会有一个函数定义(声明)过程,这个过程发生在全局上下文创建阶段,在这个过程中,fn1.[[scope]] 会保存其上层作用域的变量对象,所以此时 fn1.[[scope]]=[globalContext.VO]。

在 fn1 函数上下文创建阶段,其执行上下文如下

fn1Context={
    VO:{
        Arguments:{
            length:0
        },
        fn2:<function fn2 reference>,
        a:undefined
    },
    Scope:[fn1Context.VO,globalContext.VO]
    this:globalContext.VO
}

在 fn1 函数上下文执行阶段,其执行上下文如下

fn1Context={
    VO:{
        Arguments:{
            length:0
        },
        fn2:<function fn2 reference>,
        a:1
    },
    Scope:[fn1Context.VO,globalContext.VO]
    this:globalContext.VO
}
然后在 fn1 中调用 fn2,fn2 函数上下文被创建并入栈

同理可知,在 fn1 函数上下文创建阶段,fn2.[[scope]]=[fn1Context.VO,globalContext.VO]。

所以在 fn2 函数上下文创建阶段,其执行上下文如下

fn2Context={    VO:{        Arguments:{            0:2,            length:0
        },        b:2
        c:undefined
    },
    Scope:[fn2Context.VO,fn1Context.VO,globalContext.VO]    this:globalContext.VO
}

在 fn2 函数上下文执行阶段,其执行上下文如下

fn2Context={
    VO:{
        Arguments:{            0:2,
            length:0
        },
        b:2
        c:3
    },
    Scope:[fn2Context.VO,fn1Context.VO,globalContext.VO]    this:globalContext.VO
}
最后是各个上下文出栈

在各个上下文出栈后,其对应的变量对象会被 javascript 中的自动垃圾收集机制回收。

而我们经常说闭包能够访问其所在环境的变量,其实是因为闭包能够阻止上述变量对象被回收的过程。

关于 javascript 执行上下文系列,暂时就写这么多,以后有更深入的感悟,会继续补充的吶。

但其实我还漏了一个很重要的知识点,就是上面说的闭包啦,闭包跟变量对象以及作用域链有着千丝万缕的关系,后续我将用单独一篇文章介绍闭包,嗯哼。



作者:淘淘笙悦
链接:https://www.jianshu.com/p/1e5c85cebcc0


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP