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’。虽然两段代码执行的结果一样,但是两段代码究竟有哪些不同呢?


具体执行分析

我们首先分析第一段代码: 1.执行全局代码, 创建全局执行上下文, 全局上下文被压入 ECStack 中

ECStack = [
    globalContext
];

2.全局山下文初始化

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

2.全局上下文初始化的同时, checkscope 函数被创建, 保存作用域链到函数的内部属性 [[scope]]

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

3.执行 checkscope 函数执行上下文, checkscope函数执行上下文被压入ECStack中

ECStack = [
    checkscopeContext,
    globalContext
]

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

1.复制函数[[scope]] 属性创建作用域链, 2.用 arguments 创建活动对象, 3.初始化活动对象, 即加入形参、函数声明、变量声明, 4.将活动对象压入 checkscope 作用域链顶端。

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

// 严格模式下 this 为 undefined,在非严格模式下指向window
checkscopeContext = {
    AO: {
        arguments: {
            length: 0
        },
        scope: undefined,
        f: reference to function f(){}
    },
    Scope: [AO, globalContext.VO],
    this: undefined
}

5.执行f函数,创建f函数执行上下文,f函数执行上下文被压入ECStack中

ECStack = [
    fContext,
    checkscopeContext,
    globalContext
]

6.f函数执行上下文初始化,以下和步骤四相同:

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)中弹出

  ECStack = [
        checkscopeContext,
        globalContext
    ];

9.checkscope 函数执行完毕,checkscope 执行上下文从ECStack中弹出

  ECStack = [
        globalContext
    ];

至此,执行过程结束。