1. 什么是执行上下文?
JavaScript
是解释执行语言,但是在执行代码前,js引擎会做一些准备工作来创建代码的执行环境,所有的代码都是在执行上下文中运行的。
执行上下文(execution context
简称 EC
) 就是代码的执行环境
执行上下文 为我们的可执行代码块提供的准备工作有:
- 变量对象的定义
- 作用域链的扩展
- this绑定
2. 执行上下文有哪些类型
- 全局执行上下文
这个是程序最基础的执行上下文,任何不在函数内部的代码都在全局上下文中。全局上下文生成会做两件事:
1. 创建一个全局对象(在浏览器中是window,而Node中是global)
2. 让this指向这个全局对象
复制代码
-
函数执行上下文
每当函数调用的时候,会创建一个函数执行上下文(重复调用这个函数会产生新的执行上下文)
-
Eval 函数执行上下文
执行在
eval
函数内部的代码也会有它属于自己的执行上下文,但由于我们并不经常使用eval
,所以在这里我们不讨论它
3. 执行上下文中的内容?
在 JavaScript 代码执行前的预编译处理阶段,执行上下文会被创建,主要会发生下面3件事:
- This 绑定。
- 创建词法环境组件(
LexicalEnvironment component
) - 创建变量环境组件。(
VariableEnvironment component
)
所以执行上下文在概念上表示如下:
ExecutionContext = {
ThisBinding = <this value>,
LexicalEnvironment = { ... },
VariableEnvironment = { ... },
}
复制代码
3.1 词法环境
简单来说 词法环境 是一种持有 标识符—变量映射 的结构。这里的 标识符 指的是变量/函数的名字,而 变量 是对实际对象(包含函数类型对象)或原始数据的引用。
3.1.1 词法环境的内容?
在词法环境的内部有两个组件:
(1) 环境记录器:存储变量和函数声明的实际位置
环境记录器也有两种类型:
1. 声明式环境记录器:存储变量、函数和参数。
2. 对象环境记录器:用来定义出现在全局上下文中的变量和函数的关系。
复制代码
(2) 一个外部环境的引用:通过其访问父级词法环境(作用域)
3.1.2 词法环境的类型
(1)全局词法环境
全局词法环境是没有外部环境引用的词法环境。全局环境的外部环境引用是 null。它拥有内建的 Object/Array/等、在环境记录器内的原型函数(关联全局对象,比如 window 对象)还有任何用户定义的全局变量,并且 this
的值指向全局对象。
(2)函数词法环境
函数内部用户定义的变量存储在环境记录器中。并且引用的外部环境可能是全局环境,或者任何包含此内部函数的外部函数。
我们可以总结得出:
- 在全局环境中,环境记录器是对象环境记录器。
- 在函数环境中,环境记录器是声明式环境记录器。
3.2 变量环境
变量环境 它也是一个 词法环境 ,所以它有着词法环境的所有特性。
单独分出这个变量环境的概念是为 ES6
服务的:
在 ES6
中,词法环境组件和 变量环境 的一个不同就是前者被用来存储函数声明和变量(let
和 const
)绑定,而后者只用来存储 var
变量绑定
3.3 this
在全局执行上下文中,this
的值指向全局对象。(在浏览器中,this
引用 Window 对象)。
在函数执行上下文中,this
的值取决于该函数是如何被调用的。如果它被一个引用对象调用,那么 this
会被设置成那个对象,否则 this
的值被设置为全局对象或者 undefined
(在严格模式下)
let foo = {
baz: function() {
console.log(this);
}
}
foo.baz(); // 'this' 指向 'foo', 因为 'baz' 被对象 'foo' 调用
let bar = foo.baz;
bar(); // 'this' 指向全局 window 对象,因为没有指定引用对象
复制代码
4. 执行上下文栈
执行栈,也就是在其它编程语言中所说的“调用栈”,是一种拥有LIFO
(后进先出) 数据结构的栈,被用来存储代码运行时创建的所有执行上下文。
当 JavaScript 引擎第一次遇到你的脚本时,它会创建一个全局的执行上下文并且压入当前执行栈。每当引擎遇到一个函数调用,它会为该函数创建一个新的执行上下文并压入栈的顶部。
引擎会执行那些执行上下文位于栈顶的函数。当该函数执行结束时,执行上下文从栈中弹出,控制流程到达当前栈中的下一个上下文。
这是不是也能说明为什么外部作用域不能访问内部作用域的原因呢?
❤码字不易点个免费的赞吧❤