执行环境和变量对象的深入理解

执行环境(execution context,简称为环境)也叫执行上下文,是JavaScript中最为重要的一个概念。每当程序的执行流进入到一个可执行的代码时,就进入到了一个执行环境中。可执行代码分为三类:
    * 全局代码:这种类型的代码是在"程序"级处理的。例如加载外部的js文件或者本地  <script></script>标签内的代码。全局代码不包括任何function体内的代码。
    * 函数代码:即funtion函数代码
    * Eval代码:Eval内部的代码。

对应的执行环境也分为三种:
   * 全局执行环境:这个是最外围的代码执行环境,一旦代码被载入,引擎最先进入的就是这个环境。在浏览器中,全局执行环境就是window对象,因此所有全局属性和函数都是作为window对象的属性和方法创建的。全局执行环境直到应用程序退出时才会被销毁。
    * 函数执行环境: 当执行一个函数时,JavaScript引擎进入函数执行环境。某个执行环境中的代码执行完之后,该环境销毁,保存在其中的所有变量和函数定义也随之销毁。
    * Eval执行环境:当执行一个Eval函数时,JavaScript引擎进入Eval执行环境。

每个执行环境都有一个与之关联的变量对象(variable object),环境中定义的所有变量和函数都保存在这个对象中。执行环境是函数时,对应的变量对象叫活动对象(activation object)。当执行流进入一个函数时,函数的执行环境就会被推入环境栈中。而在函数执行完之后,栈将其环境弹出,该环境被销毁,保存在其中的所有变量和函数定义也随之被销毁,然后把控制权返回给之前的执行环境。栈的底部始终是全局环境,顶部是当前活动的执行环境。
函数执行环境的创建分为两个阶段:
1.建立阶段(发生在当调用一个函数时,但是在执行函数体内的具体代码以前),在这个阶段
   * 创建变量对象,此时的变量对象是活动对象AO
   * 作用域链被初始化(scope chain)
   * 确定this指向的对象
2.代码执行阶段:进行变量赋值,函数引用,以及执行其它代码。(此时变量名会覆盖相同的函数名)

实际上可以把执行上下文看作对象,而变量对象,作用域链和this是执行上下文的属性。
executionContextObj = {
variableObject: { /* 函数中的arguments对象, 参数, 内部的变量以及函数声明 */ },
scopeChain: { /* variableObject 以及所有父执行上下文中的variableObject */ },
this: {}
}
对于”创建变量对象”这一步,JavaScript解释器主要做了下面的事情:
   * 根据函数的参数,创建并初始化arguments object,然后把形参作为属性,实参作为属性值。(在全局环境中不存在arguments对象,也没有参数这几个属性)
    * 扫描函数内部代码,查找函数声明(Function declaration)。 对于所有找到的函数声明,将函数名和函数引用存入VO/AO中。如果VO/AO中已经有同名的函数或变量名,那么就进行覆盖。
    * 扫描函数内部代码,查找变量声明(Variable declaration)。对于所有找到的变量声明(用var声明的变量),将变量名存入VO/AO中,并初始化为”undefined”。如果VO/AO中已经存在同名的变量,就什么也不做,继续扫描。
在建立阶段,变量对象的属性除了arguments,函数的声明,以及参数被赋予了具体的属性值,其它的变量属性默认的都是undefined。而且函数名会覆盖相同的变量名。
例如:
function test(x,y){
a = 10;
var b = 10;
var c = function add(){
};
console.log(x+y);
}
test(1,2);
对于上面的代码,在”建立阶段”,可以得到下面的活动对象,其中变量a和函数add不在活动对象里面。
AO = {
arguments:{
0:1,
1:2,
callee:function test(x,y),
length:2,
。。。。
},
x:1,
y:2,
b:undefined,
c:undefined,
test:function test(x,y)
}
对于VO/AO,是有下面两种特殊情况的:
* 函数表达式(与函数声明相对)不包含在VO/AO之中
* 没有使用var声明的变量(这种变量是,”全局”的声明方式,只是给Global添加了一个属性,并不在VO/AO中)
抽象变量对象VO (变量初始化过程的一般行为)

╠══> 全局上下文变量对象GlobalContextVO
║ (VO === this === global)

╚══> 函数上下文变量对象FunctionContextVO
(VO === AO, 并且添加了<arguments>和<formal parameters>)
全局执行环境的创建和函数执行环境的创建基本相同,唯一不同的就是变量对象。全局执行环境创建的变量对象不包含arguments对象,也没有参数这个属性。全局执行环境创建的变量对象就是全局对象。
全局对象:全局对象(Global object) 是在进入任何执行上下文之前就已经创建了的对象。这个对象只存在一份,它的属性在程序中任何地方都可以访问,全局对象的生命周期终止于程序退出那一刻。全局对象初始创建阶段将Math、String、Date、parseInt作为自身属性,等属性初始化,同样也可以有额外创建的其它对象作为属性(其可以指向到全局对象自身)。而全局对象的window属性就可以引用全局对象自身(当然,并不是所有的具体实现都是这样):
global = {
Math: <...>,
String: <...>
...
...
window: global //引用自身
};
当访问全局对象的属性时通常会忽略掉前缀,这是因为全局对象(即global对象)是不能通过名称直接访问的。不过我们依然可以通过全局上下文的this来访问全局对象,同样也可以递归引用自身。例如,DOM中的window。因此,全局上下文的变量对象(VO)就是全局对象(Global Object)。即:VO(globalContext) === global; 在web浏览器中全局对象就是Window对象。


转载于:https://juejin.im/post/59cce3656fb9a00a4d53fb71

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值