词法作用域、作用域链、执行上下文栈

var globalVar = 1;
function outer(param) {
    var a = 3 + param;
    function inner(param) {
        var b = 4;
        return a + b + param;
    }
    return inner(2);
}
outer(1);

1,创建全局词法作用域,创建全局执行上下文,并入执行上下文栈。

window.AO = {
    globalVar: 1,
    outer: function () {...}
}
window.[[scope]] = window.AO;

EC_window = {
    AO: window.AO,
    scope: window.[[scope]],
    this: this
}
ECS.push(EC_window);
  • 全局执行上下文会在页面打开后一直存在,直到页面关闭,所以全局执行上下文会一直存在栈底。
  • 全局代码在代码执行的最初就开始执行,所以一开始创建的就是AO,不存在VO的状态。

2,定义outer,创建outer的词法作用域

这一步的执行是由于在第1步中执行全局代码时遇到了outer函数的定义。

outer.VO = {
    arguments: {
        length: 0
    },
    inner: function () {...}
}
outer.[[scope]] = [
    window.AO
]

3,准备执行outer,创建outer的执行上下文,并入执行上下文栈。

这一步的执行同样是由于第1步中执行全局代码时遇到了outer的调用。

EC_outer = {
    AO: outer.AO,
    scope: [
        outer.[[scope]],
        outer.AO
    ],
    this: this
}
ECS.push(EC_outer);

4,执行outer,修改outerOA

outer.AO = {
    arguments: {
        param: 1,
        a: 4,
        length: 2
    }
    inner: function () {...}
}

5,定义inner,创建inner的词法作用域。

这一步的执行是由于第4步中遇到了inner的定义。

inner.VO = {
    arguments: {
        length: 0
    },
    b: undefined
}
inner.[[scope]] = [
    window.AO,
    outer.AO
]

6,准备执行inner,创建inner的执行上下文,并入执行上下文栈。

这一步的执行同样是由于第4步中执行代码时遇到了inner的调用。

EC_inner = {
    AO: inner.AO,
    scope: [
        inner.[[scope]],
        inner.AO
    ]
}
ECS.push(EC_inner);

7,执行inner,修改innerAO

inner.AO = {
    arguments: {
        param: 2,
        length: 1
    },
    b: 4
}

inner的执行过程中共需要abparam三个变量。

  • 首先会在inner执行上下文的scope的最内层(最近的作用域)inner.AO中查找这三个变量。从AO.arguments中查找到param为2,从AO中查找到b为4。
  • AO中没有找到a变量,所以向外一层inner.[[scope]]中查找,查找方法相同,依然从inner.[[scope]]最外层outer.AO中查找,此时找到a为4。
  • 如果仍然有没有找到的变量,继续按此方法查找,直到找到变量,或者查找到最外层全局词法作用域中依然没有该变量(此时确定该变量未定义)。
  • 此时已经拥有abparam三个变量的值分别为2,4,4,返回计算结果 10。

8,inner执行结束,出执行上下文栈。

ECS.pop();

return语句执行后,inner的执行就结束了。inner的执行上下文就会弹出执行上下文栈。

9,outer执行结束,出执行上下文栈。

ECS.pop();

inner的执行结束后,outer的执行遇到return,所以outer的执行也结束了。outer的执行上下文就会弹出执行上下文栈。

此时的执行上下文栈中只剩全局执行上下文。

10,关闭页面,全局执行上下文出执行上下文栈。

ECS.pop();

此时执行上下文栈清空,运行结束。

最后更新时间: 3/21/2019, 10:08:19 PM