Js 执行上下文

Javascript有三种代码运行环境:Global, Function 和 Eval函数内部的执行环境。为了表示不同的运行环境,JavaScript中有一个执行上下文(Execution context,EC)的概念,也称执行环境。
当JavaScript代码执行的时候,执行流会进入到相应的执行环境,该执行环境被推入到一个环境栈中,函数执行之后,js引擎将其环境从栈中弹出,将控制权返回给之前的执行环境。
全局执行环境是默认的最外层的执行环境,在执行环境栈的最底部。

function outerFunc() {
    console.log('In outer function EC!');

    function innerFunc() {
        console.log('In inner function EC!');
    }

    innerFunc();
}

outerFunc();
console.log('In global EC');

当执行innerFunc函数时,该环境栈是
这里写图片描述

Javascript执行环境中的重要属性

每个执行环境有三个重要的属性:变量对象(Variable Object)、作用域链(Scope Chain)、this指针。
这里写图片描述

活动对象(Activation object)和变量对象(Variable object)

只有全局环境的变量对象允许通过VO的属性名称间接访问;在函数执行上下文中,VO是不能直接访问的,此时由激活对象(Activation Object, 缩写为AO) 扮演VO的角色。激活对象是在进入函数上下文时刻被创建的,它通过函数的arguments属性初始化。

对于VO和AO的关系可以理解为,VO在不同的Execution Context中会有不同的表现:当在Global Execution Context中,可以直接使用VO;但是,在函数Execution Context中,AO就会被创建。

Javascript执行环境阶段

Javascript引擎创建执行环境分为两个阶段:创建阶段激活/执行阶段
创建阶段是Js引擎已经调用一个函数但函数还未开始执行的阶段,会创建激活对象或者变量对象、Scope chain、设置this指针的值。执行阶段Js引擎会设置变量的值、函数的引用,然后解释和执行代码。

function funA (a, b) {
  var c = 3;

  var d = 2;

  d = function() {
    return a - b;
  }
}

funA(3, 2);

在A函数被调用但还未执行时,Js引擎为A函数创建了执行环境对象executonContextObj,如下:

funAExecutionContextObj = {
 variableObject: {}, // All the variable, arguments and inner function details of the funA
 scopechain: [], // List of all the scopes inside which the current function is
 this // Value of this 
}

对于创建激活对象或者变量对象,Js引擎具体做法是:

1.根据函数参数,创建并初始化arguments object;
2.扫描函数内部代码,查找函数声明(Function declaration)
   - 对于所有找到的函数声明,将函数名和函数引用存入VO/AO中
  - 如果VO/AO中已经有同名的函数,那么就进行覆盖
3.扫描函数内部代码,查找变量声明(Variable declaration)
  - 找到所有的变量声明,将变量名存入VO/AO中,并初始化为’undefined’;
  - 如果变量名称跟已经声明的形式参数或函数相同,则变量声明不会干扰已经存在的这类属性

针对上面的例子,其中variableObject(变量对象)属性包含了函数内部的变量、函数声明以及arguments形参。具体为:

variableObject = {
  arguments : {
    0: a,
    1: b,
    length: 2
  },
  a: 3,
  b: 2
  c: undefined,
  d: undefined then pointer to the function defintion of d
}

执行阶段,Js引擎扫描整个函数,更新变量值并执行代码。这个时候执行环境中的variableObject变为:

variableObject = {
  arguments : {
    0: a,
    1: b,
    length: 2
  },
  a: 3,
  b: 2
  c: 3,
  d: undefined then pointer to the function defintion of d
}

对于变量对象VO,是有下面两种特殊情况的:

函数表达式(与函数声明相对)不包含在VO之中(此处有疑问)
没有使用var声明的变量不在VO中(这种变量是,”全局”的声明方式,只是给Global添加了一个属性)

(function(){
    console.log(bar);
    console.log(baz);

    bar = 20;
    console.log(window.bar);
    console.log(bar);

    function baz(){
        console.log("baz");
    }

})()

运行这段代码会得到”bar is not defined(…)”错误。当代码执行到”console.log(bar);”的时候,会去AO中查找”bar”。但是,根据前面的解释,函数中的”bar”并没有通过var关键字声明,所有不会被存放在AO中,也就有了这个错误。
注释掉”console.log(bar);”,再次运行代码,就不会报错。”bar”在”激活/代码执行阶段”被创建。

参考:
https://hackernoon.com/execution-context-in-javascript-319dd72e8e2c
http://www.cnblogs.com/wilber2013/p/4909430.html
https://github.com/mqyqingfeng/Blog/issues/8

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值