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的执行上下文
相关文章推荐
- Javascript学习---2、执行环境,作用域
- JavaScript执行环境及作用域
- javascript的执行环境及作用域(一)
- javascript 原型链、执行环境、作用域链、实例对象之间的关系
- javascript的执行环境及作用域概念总结与理解
- javascript执行环境
- JavaScript学习-执行环境和作用域
- JavaScript执行环境
- JavaScript执行环境和作用域
- JavaScript执行环境及作用域
- javascript中执行环境和作用域链的概率
- JavaScript中的执行环境
- 【个人笔记重点,不作为参考】主题:javascript 执行环境及作用域
- 浏览器环境下JavaScript脚本加载与执行探析之defer与async特性
- JavaScript语言精粹--执行环境及作用域,this
- Javascript 作用域链 活动对象 执行环境 与 this 的纠结 总结~
- 浏览器环境下JavaScript脚本加载与执行探析之动态脚本与Ajax脚本注入
- Javascript中的执行环境和作用域细讲
- 关于JavaScript的执行环境与作用域的解读
- JavaScript执行环境和作用域链