我们来详细讲解一下“详解JavaScript中的执行上下文及调用堆栈”的攻略。
什么是执行上下文
当 JavaScript 代码执行一段可执行代码时,会创建对应的执行上下文。执行上下文可以理解为是当前 JavaScript 代码的执行环境或者说是当前代码执行时的上下文环境,它包含了当前执行代码所需的所有变量、函数、参数等信息。如果把生活中的场景来理解,执行上下文就相当于一个人在进行某个行动的情境,不同的情境会导致这个人采取不同的行动。
执行上下文的类型
在 JavaScript 中,一共有 3 种不同类型的执行上下文:
- 全局执行上下文:默认情况下,JavaScript 代码会在全局环境中被执行,此时就会创建一个全局执行上下文。
- 函数执行上下文:当函数被调用时,就会创建一个对应该函数的执行上下文。
- Eval 函数执行上下文:执行 eval 函数时,会创建一个对应该函数的执行上下文。
执行上下文的创建过程
当 JavaScript 代码开始执行时,首先会创建一个全局执行上下文。随后,当函数被调用时,就会依次按照下面的步骤创建函数执行上下文:
- 创建函数的 AO 对象(Activation Object),该对象包含了函数内部声明的变量、函数等信息;
- 创建作用域链(Scope Chain),该作用域链指向外部环境的变量对象;
- 确定 this 的指向。
同时,一旦执行上下文被创建完毕,就会被推入到调用堆栈(Call Stack)中。
调用堆栈
调用堆栈(Call Stack)是一种数据结构,它类似于一个箱子,被用来管理在执行上下文中代码的执行顺序。每当创建一个新的执行上下文时,就会被推入调用堆栈的顶部,当该执行上下文执行完毕后,就会从调用堆栈中弹出并清除。
示例1:全局执行上下文
我们来看一个示例,如下所示:
var a = 'Hello, World!';
function foo(){
console.log(a);
}
foo();
在以上代码中,当 JavaScript 解释器开始执行该代码时,会首先创建一个全局执行上下文。随后,在全局执行上下文中,会先定义变量 a,并给其赋值 'Hello, World!'。接下来,会定义函数 foo,但是由于 JavaScript 并不会立刻执行函数,所以在执行 foo 之前,全局执行上下文将一直存在于调用堆栈的顶部。
当执行到 foo 函数时,在函数 foo 自己的执行上下文中也会创建 AO 对象,此时 AO 对象中并不包含变量 a,而是因为 foo 函数被定义在全局的作用域内,所以它可以访问到全局作用域中的变量 a。因此,在函数 foo 的作用域链中,会把全局作用域对象也加入进去,从而顺利地访问到了 a 这个变量。最终的输出结果就是 'Hello, World!'。
示例2:嵌套函数调用
我们来看另一个示例,如下所示:
function outer() {
inner();
console.log('outer function');
};
function inner() {
console.log('inner function');
};
outer();
在以上代码中,当执行到 outer 函数时,会创建 outer 的执行上下文,并将其推入调用堆栈中,接着调用 inner 函数。在调用 inner 函数时,会创建 inner 的执行上下文,并将其推入堆栈中。此时,调用堆栈的顶部是 inner 函数的执行上下文,而 outer 函数的执行上下文位于其下方。
当执行完 inner 函数后,该执行上下文会从调用堆栈中弹出并被销毁,此时调用堆栈的顶部变成了 outer 函数的执行上下文,最终输出结果为 'inner function' 和 'outer function'。
通过以上两个示例,我们可以更加清晰地理解 JavaScript 中的执行上下文及调用堆栈。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解JavaScript中的执行上下文及调用堆栈 - Python技术站