什么是执行上下文?
其实,执行上下文,只是一个比较抽象的概念,待我慢慢道来。
打个比方:比如你尿急,是不是得上厕所。尿急是一个动作,就相当于我们的程序代码,那么厕所是不是一个环境,你总不能随地大小便吧。所以这个环境就是指我们程序执行的环境,从抽象层面上讲就是你的给程序代码一个可以执行环境。
比较专业的术语如下:
简而言之,执行上下文是评估和执行 JavaScript 代码的环境的抽象概念。每当 Javascript 代码在运行的时候,它都是在执行上下文中运行。
执行上下文的类型
一般分为三种:
- 全局执行上下文:一般是指向 window 对象,一个程序只有一个全局上下文,指在浏览器的情况下。
- 函数执行上下文:每当函数执行的时候,都会创建一个属于函数的上下文执行环境,但是函数的执行上下文,可以有多个,因为函数里面还可以再嵌套函数。
- eval执行上下文:平常不是很常用,我们不准备讲。
执行栈
可以这么理解,执行栈就是一个队列,就好像我们放羽毛球进羽毛球桶一样,总是先放进去的只能后面使用,后放进去的先使用。
执行栈的目的就是用来存储我们前面所说的各种执行上下文。
js 引擎在执行代码的时候,会先执行放在执行栈前面的执行上下文,执行完就会释放掉,继续执行其他执行上下文,直到全局执行上下文执行完毕。
先来看一段代码:
代码语言:javascript复制let a = 'Hello World!';
function first() {
console.log('Inside first function');
second();
console.log('Again inside first function');
}
function second() {
console.log('Inside second function');
}
first();
console.log('Inside Global Execution Context');
我们先来解析一下整个流程:第一步:首先是创建执行上下文 js 引擎在执行脚本的时候,会先创建全局执行上下文,压入执行栈底部 然后碰到 first()
函数创建 first
函数执行上下文,将其压入执行栈中。
当 first()
执行时,碰到 second()
函数创建 second
函数执行上下文,将其压入执行栈中。
第二步:执行代码 首先先是执行 first()
碰到 second()
执行,所以 second()
函数执行完毕销毁,再到 first()
函数执行完毕销毁,最后再到 全局执行完毕
// 打印顺序如下
Inside first function
Inside second function
Again inside first function
Inside Global Execution Context
怎么创建执行上下文?
创建执行上下文有两个阶段:1) 创建阶段 和 2) 执行阶段。
- this 值的决定,即我们所熟知的 This 绑定。
- 创建词法环境组件。
- 创建变量环境组件。
ExecutionContext = {
ThisBinding = <this value>,
LexicalEnvironment = { ... },
VariableEnvironment = { ... },
}
This 绑定:
在全局执行上下文中,this 的值指向全局对象。(在浏览器中,this引用 Window 对象)。在函数执行上下文中,this 的值取决于该函数是如何被调用的。如果它被一个引用对象调用,那么 this 会被设置成那个对象,否则 this 的值被设置为全局对象或者 undefined(在严格模式下)。例如:
代码语言:javascript复制let foo = {
baz: function() {
console.log(this);
}
}
foo.baz(); // 'this' 引用 'foo', 因为 'baz' 被
// 对象 'foo' 调用
let bar = foo.baz;
bar(); // 'this' 指向全局 window 对象,因为
// 没有指定引用对象