您的位置:首页 > Web前端 > JavaScript

JavaScript 的执行环境

2018-03-31 10:05 309 查看
  
执行环境
(execution context,有时也被叫做
执行上下文
)是 JavaScript 中最重要而且是最基本的一部分内容。在你搞清楚执行环境后,会对你弄清楚作用域链、变量提升、this这些核心概念起着决定性的作用。

  希望你能在读完本文后,能够弄清楚解释器做了什么,为什么函数和变量能在声明前使用以及他们的值是何时被决定的。

执行环境(EC)

  执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。每个执行环境都有一个与之关联的变量对象(
variable object
,一般简写为
VO
,环境中定义的所有变量和函数都保存在这个对象中。虽然我们编写的代码无法访问这个对象,但解析器在处理数据时会在后台使用它。

[align=right]——来自红宝书对执行环境的定义[/align]

在 JavaScript 中,可执行的 JavaScript 代码分为三种

Global Code(全局级别的代码)

JavaScript 代码开始运行的默认环境,即全局的、不在任何函数里面的代码

Function Code(函数级别的代码)

代码进入一个JavaScript函数,运行函数体中的代码,即用户自定义函数中的函数体代码

Eval Code(Eval的代码)

eval 函数中动态执行的代码

跳过 Eval Code,只说全局执行环境和函数执行环境。

全局执行环境

  全局执行环境是最外围的一个执行环境。在 Web 浏览器中,全局执行环境被认为是 window 对象,因此所有全局变量和函数都是作为window对象的属性和方法创建的。代码载入浏览器时,全局执行环境被创建(当我们关闭网页或者浏览器时全局执行环境才被销毁)。

函数执行环境

  每个函数都有自己的执行环境,当执行进入一个函数时,函数的执行环境就会被推入一个
执行环境栈
的顶部并获取执行权。当这个函数执行完毕,它的执行环境又从这个栈的顶部被删除,并把执行权并还给之前执行环境。

  这里我们来看个例子,来看一看这个
环境栈
究竟是如何运作的:

<script>

4000
var scope = "global";
function fn1(){
return scope;
}
function fn2(){
return scope;
}
fn1();
fn2();
</script>


环境栈的运作情况:

![这里写图片描述](https://img-blog.csdn.net/20180331100221830?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3p3a2trazE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)

  当 JavaScript 代码执行时,第一个进入的总是默认的 **全局执行环境**(在 Web 浏览器中也就是 window 对象)。
  对于每个执行环境都有三个重要的属性,**变量对象(Variable object,VO)**、**作用域链(Scope chain)**和 **this**。这三个属性和代码运行的行为有很重要的关系。
  下面我们首先来看一看 `VO / AO`这个概念。

VO 和 AO

变量对象(Variable object)

  每个
执行环境
都有一个与之关联的
变量对象
环境中定义的所有变量和函数都保存在这个对象中

  从上面的定义中,我们可以知道一般 VO 会包含下面的三类信息:

变量声明(var,Variable Declaration)

函数声明(FD,Function Declaration)

函数的形参

举个例子:

<script type="text/javascript">
var a = "global var";

function foo(x1) {
var x2 = "local var";
}
</script>


  在这个程序中,全局执行环境中的 VO 就有两个部分:

1. 通过变量声明的变量
a


2. 通过函数声明的函数
foo


活动对象(Activation object)

  只有全局变量的变量对象允许通过 VO 的属性名称间接访问(
window对象
);在函数执行环境中,VO 是不能直接访问的,则将其
活动对象(activation object)
作为变量对象。

  AO 是在进入函数的执行环境时创建的,并为该对象初始化一个 arguments 对象(这个对象在全局环境是不存在的!)。

arguments 对象是函数环境里的活动对象 AO 中的内部类数组对象,它包括以下的属性:

 1.callee:指向当前函数的引用

 2.length:真正传递的参数的个数

 3.properties-indexes:函数的参数值(按参数列表从左到右排列)

(对 arguments 对象的介绍可以移步 JavaScript arguments对象详解

在上面 VO 例子中,当开始执行到 foo 的时候,就会有一个 foo 的 AO 被创建,这个活动对象由两个部分组成:

1. 初始化生成的
arguments 对象


2. 通过变量声明的变量
x2


再看执行环境

当一段 JavaScript 代码运行时,解释器(编译器)会创建执行环境,这里会有两个阶段:

创建阶段
编译阶段
,当函数被调用,但是开始执行函数内部代码之前)

创建 Scope chain

创建 VO / AO

设置 this 的值

代码执行阶段


设置变量的值、函数的引用,然后解释、执行代码

对于创建 VO / AO,JavaScript 编译器主要做了下面的事:

根据函数的参数,创建并初始化
arguments对象


扫描函数内部代码,查找
函数声明(Function declaration)


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

如果 VO / AO 中已经有同名的函数(变量),那么就进行覆盖

扫描函数内部代码,查找变量声明(Variable declaration)

对于所有找到的变量声明,将变量名存入VO/AO中,并初始化为”undefined”

如果变量名称跟已经声明的形参或函数相同,则变量声明不会干扰已经存在的这类属性

:第2、3步就是
提升(hoisting)
(详细介绍可移步: JavaScript中的变量提升和函数提升

参考文章:JavaScript关于作用域、作用域链和闭包的理解

     JavaScript的执行上下文
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: