java script 运行环境_JavaScript执行环境

执行环境(Execution Context,也称为"执行上下文")是JavaScript中最为重要的一个概念。执行环境定义了变量或函数有权访问的其它数据,决定了各自的行为。当JavaScript代码执行的时候,会进入不同的执行环境,这些不同的执行环境就构成了执行环境栈。

JavaScript中主要存在三种执行环境:

全局执行环境

JavaScript代码执行的默认环境。通常被默认为window对象,所有的全局变量和函数都作为window对象的属性和方法存在。当执行环境中的代码执行完毕之后,执行环境被销毁,其中的所有变量和函数也随之销毁。对于全局执行环境来说,当关闭网页或浏览器时,该环境被销毁。

函数执行环境

当执行一个JavaScript函数时,函数的环境被推入环境栈中,执行完毕之后,栈将执行环境推出,将控制权转交给之前的执行环境。

Eval环境

执行eval()函数时创建。

对于执行环境栈,请看如下代码:

var a = "global";

function example(){

console.log(a);

}

function outer(){

var b = "outer";

console.log(b);

function inner(){

var c = "inner";

console.log(c);

example();

}

inner();

}

outer();

代码首先进入全局执行环境,然后依次进入outer,inner和example的执行环境,执行环境栈可以表示为:

43d8f569806a3a39fc40508108055e65.png

每个执行环境都有三个重要的属性,变量对象(VO)、作用域链(scope chain)和this。下面首先看一下变量对象。

变量对象和活动对象(VO和AO)

变量对象

每个执行环境都有一个与之关联的变量对象(variable object),环境中定义的所有变量和函数都保存在这个对象中。当代码在一个环境中执行时,会创建当前变量对象的一个作用域链(scope chain)。作用域链的最前端,始终是当前执行环境的变量对象。如果执行环境是函数,则其活动对象(activation object)作为变量对象。作用域链的下一个变量对象来自于父执行环境,而再下一个变量对象来自于父环境的外部环境,以此类推构成完整的作用域链,而最外层的变量对象始终是全局执行环境的变量对象。

一般来说,变量对象(VO)中包含以下信息:

变量

函数声明

函数的形参

当JavaScript代码执行的时候,如果试图寻找一个变量或函数,就会首先寻找VO。对于前面提到的代码,全局执行环境的VO如下所示:

c953d155262f416a68f384d0e35df0b4.png

对于VO来说,函数表达式不包含在VO中,没有使用var声明的变量也不包含在VO中,这种方式只是给Global添加了一个属性。

活动对象

只有全局执行环境的变量对象允许通过VO的属性名称间接访问。但在函数执行环境中,VO是不允许被直接访问的。此时,由活动对象(Activation Object,简称AO)扮演VO的角色。活动对象在进入函数执行环境时被创建,它通过函数的arguments属性初始化,其中Arguments Objects是函数执行环境中活动对象AO的内部对象。

VO和AO的关系,简单点说就是,VO在不同的执行环境中有不同的变现形式。在全局执行环境中,可以直接使用VO;但是在函数执行环境中,AO被创建。

在上面的代码例子中,当开始执行outer函数的时候,outer函数的AO被创建如下图所示:

a8b4a78647148a4caee0f5d468e042e7.png

执行环境的具体过程

当进入一个执行环境的时候,JavaScript解释器会创建新的执行环境,但具体是怎么做的呢?主要分为两个阶段:

创建阶段

创建作用域链

创建VO/AO

设置this的值

执行阶段

设置变量的值

设置函数的引用

解释执行代码

对于"创建VO/AO"这一步,JavaScript解释器主要做了下面的事情:

根据函数参数,创建并初始化arguments object

根据函数内部代码查找函数声明

对于找到的所有函数声明,将函数名和引用全部存入VO/AO

如果存在同名函数,进行覆盖

根据函数内部代码查找变量声明

对于找到的所有变量声明,全部存入VO/AO,并初始化为"undefined"

如果变量名称和已经声明的形参或函数相同,那么变量声明不会干扰这类属性

看下面的例子:

function example(p) {

var a = 'hello';

var b = function b() {...};

function c() {...}

}

example(2);

对于上面的例子,在执行环境创建阶段,会得到如下的执行环境对象:

exampleExecutionContext={

scopeChain: {...},

VO:{

arguments:{

0:2,

length:1

}

p:2,

c:pointer to function c()

a:undefined,

b:undefined

},

this: {...}

}

在代码执行阶段,环境对象会被更新,如下所示:

exampleExecutionContext={

scopeChain: {...},

VO:{

arguments:{

0:2,

length:1

}

p:2,

c:pointer to function c()

a:'hello',

b:pointer to function b()

},

this: {...}

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值