执行环境是JavaScript 中最为重要的一个概念。执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。
#一. 背景介绍
执行环境是什么
执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。 每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。 我们编写的代码是无法访问这个对象的,但解析器在处理数据时会在后台使用它。
全局执行环境
全局执行环境是最外围的一个执行环境,在Web浏览器中,全局执行环境被认为是window对象, 因此所有全局变量和函数都是作为window对象的属性和方法来创建的。 某个执行环境中的所有代码执行完毕后,该环境就会被销毁,保存在其中的所有变量和函数定义也随之销毁。
二.知识剖析
如果所在环境是函数,那么就会把这个函数的活动对象作为变量对象(在函数中,变量对象==活动对象)。
一般而言,函数执行过程,可以分成两步:1.进入执行环境;2.执行代码。
环境栈的定义
当执行流进入一个函数时,函数的环境就会被推入一个环境栈中。执行之后, 再从环境栈中弹出。
原理解析
JavaScript解释器在浏览器中是单线程的,这意味着浏览器在同一时间内只执行一个事件, 对于其他的事件我们把它们排队在一个称为 执行栈的地方。
我们已经知道,当浏览器第一次加载你的script,它默认的进了全局执行环境。 如果在你的全局代码中你调用了一个函数,那么顺序流就会进入到你调用的函数当中, 创建一个新的执行环境并且把这个环境添加到执行栈的顶部。
如果你在当前的函数中调用了其他函数,同样的事会再次发生。 执行流进入内部函数,并且创建一个新的执行环境,把它添加到已经存在的执行栈的顶部。 浏览器始终执行当前在栈顶部的执行环境。一旦函数完成了当前的执行环境,它就会被弹出栈的顶部, 把控制权返回给当前执行环境的下个执行环境。
三.问题与讨论
什么是作用域链
作用域链与执行上下文相关,是内部上下文所有变量对象(包括父变量对象)的列表,用于变量查询。 作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。
- 代码在执行环境中执行时,执行环境会为变量对象创建作用域链。
- 作用域链是由变量对象组成的数据对象链。
- 作用域链的前端,始终是当前函数执行环境的变量对象。
- 作用域链的最后端,始终是全局执行环境的变量对象。
函数创建的过程
- 在一个函数被定义的时候, 会将它定义时刻的scope chain链接到这个函数对象的
- [[Scopes]]属性,函数可以通过这个属性来访问更高层的作用域。
- [[Scopes]]是所有父变量对象的层级链,处于当前函数上下文之上,在函数创建时存于其中。
- [[Scopes]]在函数创建时被存储--静态(不变的),永远永远,直至函数销毁。
- [[Scopes]]存储的是定义时刻的作用域链,是函数本身所依赖的变量对象其所在环境的 [[Scopes]]组成的。
什么是标识符的解析
标识符解析是沿着作用域链一级一级向上(外)搜索标识符的过程。搜索过程始终从作用域链的前端开始,然后逐级向后回溯,直至找到标识符为止。
其中内部环境可以通过作用域链访问所有的外部环境,但外部环境不能访问内部变量环境中的任何变量和函数。这些环境之间的练习是线性的,有次序的。每个环境变量都可以向上搜索作用域链,以查询变量和函数名;反之则是不行。