JavaScript深切之实行上下文

JavaScript深切系列第七篇,连系之前所讲的四篇文章,以威望指南的demo为例,细致解说当函数实行的时刻,实行上下文栈、变量对象、作用域链是怎样变化的。

媒介

《JavaScript深切之实行上下文栈》中讲到,当 JavaScript 代码实行一段可实行代码(executable code)时,会建立对应的实行上下文(execution context)。

关于每一个实行上下文,都有三个主要属性:

  • 变量对象(Variable object,VO)

  • 作用域链(Scope chain)

  • this

然后分别在《JavaScript深切之变量对象》《JavaScript深切之作用域链》《JavaScript深切之从ECMAScript范例解读this》中解说了这三个属性。

浏览本文前,假如对以上的观点不是很清晰,愿望先浏览这些文章。

由于,这一篇,我们会连系着一切内容,讲讲实行上下文的细致处置惩罚历程。

思索题

《JavaScript深切之词法作用域和动态作用域》中,提出如许一道思索题:

var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f();
}
checkscope();
var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f;
}
checkscope()();

两段代码都邑打印’local scope’。虽然两段代码实行的效果一样,然则两段代码终究有哪些差别呢?

紧接着就鄙人一篇《JavaScript深切之实行上下文栈》中,讲到了二者的区分在于实行上下文栈的变化不一样,但是,假如是如许笼统的回复,依旧显得不够细致,本篇就会细致的剖析实行上下文栈和实行上下文的细致变化历程。

细致实行剖析

我们剖析第一段代码:

var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f();
}
checkscope();

实行历程以下:

1.实行全局代码,建立全局实行上下文,全局上下文被压入实行上下文栈

    ECStack = [
        globalContext
    ];

2.全局上下文初始化

    globalContext = {
        VO: [global, scope, checkscope],
        Scope: [globalContext.VO],
        this: globalContext.VO
    }

2.初始化的同时,checkscope 函数被建立,保留作用域链到函数的内部属性[[scope]]

    checkscope.[[scope]] = [
      globalContext.VO
    ];

3.实行 checkscope 函数,建立 checkscope 函数实行上下文,checkscope 函数实行上下文被压入实行上下文栈

    ECStack = [
        checkscopeContext,
        globalContext
    ];

4.checkscope 函数实行上下文初始化:

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

  2. 用 arguments 建立运动对象,

  3. 初始化运动对象,即到场形参、函数声明、变量声明,

  4. 将运动对象压入 checkscope 作用域链顶端。

同时 f 函数被建立,保留作用域链到 f 函数的内部属性[[scope]]

    checkscopeContext = {
        AO: {
            arguments: {
                length: 0
            },
            scope: undefined,
            f: reference to function f(){}
        },
        Scope: [AO, globalContext.VO],
        this: undefined
    }

5.实行 f 函数,建立 f 函数实行上下文,f 函数实行上下文被压入实行上下文栈

    ECStack = [
        fContext,
        checkscopeContext,
        globalContext
    ];

6.f 函数实行上下文初始化, 以下跟第 4 步雷同:

  1. 复制函数 [[scope]] 属性建立作用域链

  2. 用 arguments 建立运动对象

  3. 初始化运动对象,即到场形参、函数声明、变量声明

  4. 将运动对象压入 f 作用域链顶端

    fContext = {
        AO: {
            arguments: {
                length: 0
            }
        },
        Scope: [AO, checkscopeContext.AO, globalContext.VO],
        this: undefined
    }

7.f 函数实行,沿着作用域链查找 scope 值,返回 scope 值

8.f 函数实行终了,f 函数上下文从实行上下文栈中弹出

    ECStack = [
        checkscopeContext,
        globalContext
    ];

9.checkscope 函数实行终了,checkscope 实行上下文从实行上下文栈中弹出

    ECStack = [
        globalContext
    ];

第二段代码就留给人人去尝试模仿它的实行历程。

var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f;
}
checkscope()();

不过,鄙人一篇《JavaScript深切之闭包》中也会说起这段代码的实行历程。

下一篇文章

《JavaScript深切之闭包》

相干链接

《JavaScript深切之词法作用域和动态作用域》

《JavaScript深切之实行上下文栈》

《JavaScript深切之变量对象》

《JavaScript深切之作用域链》

《JavaScript深切之从ECMAScript范例解读this》

主要参考

《一道js面试题激发的思索》

本文写的太好,给了我许多启示。感激涕零!

深切系列

JavaScript深切系列目次地点:https://github.com/mqyqingfeng/Blog

JavaScript深切系列估计写十五篇摆布,旨在帮人人捋顺JavaScript底层学问,重点解说如原型、作用域、实行上下文、变量对象、this、闭包、按值通报、call、apply、bind、new、继续等难点观点。

假如有毛病或许不严谨的处所,请务必赋予斧正,非常谢谢。假如喜好或许有所启示,迎接star,对作者也是一种勉励。

    原文作者:冴羽
    原文地址: https://segmentfault.com/a/1190000009063218
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞