我是JS新手,正在学习JS中执行上下文的角色,并问自己JS中执行上下文有什么好处,以及为什么JS通过执行上下文运行。 第二个问题是我们所知道的全局和功能执行上下文,每个上下文都有两个阶段:创建阶段和执行阶段。那么,为什么我们需要这两个阶段?拥有它们的意义何在?
答案 0 :(得分:1)
“执行上下文”的概念提供了一种推理方法,用于推理在创建和执行全局环境或调用函数时发生的情况。它是局部变量(在全局环境下为全局变量),参数(对于函数)等的概念性容器。可以编写JavaScript引擎,而实际上不包含任何称为“执行上下文”的对象,只要它实现了与规范定义的执行上下文行为一致的语言。
执行上下文可以帮助解释的一件事是 closures 的行为。即使在与上下文相关的函数调用完成之后,在给定的执行上下文中创建的函数(在概念上)也具有对该上下文的引用:
function foo(answer) {
return function say() {
console.log(answer);
};
}
const s = foo(42);
s(); // 42
之所以可行,是因为函数say
引用了创建它的foo
的调用上下文(嗯,更具体地说,是称为“词法环境”的事物)。在foo
返回之后,该词法环境继续存在,因为某些内容仍对其进行引用(say
)。因此,随后向say
的调用就可以了。
具有两个阶段的原因是允许在声明标识符之前使用标识符。这主要用于函数声明:
main();
function main() {
console.log("Worked");
}
第一个阶段处理函数声明(和var
语句),然后分步阶段运行代码。没有第一阶段,上面的代码将从main();
开始失败,因为将main
声明为未声明。当然,通过上面的简单示例,您可以将main();
调用移至函数声明之后的 ,但是更复杂的情况很难以这种方式解决。没有两个阶段的语言(例如,早期的C)必须提供一种“向前声明”将在以后定义的事物的机制。具有两个阶段意味着JavaScript不必具有这些阶段。 (为公平起见,C与JavaScript的不同之处在于,即使标识符在函数内的代码中,它也需要知道所有标识符在编译过程中所引用的内容。因此,它需要前向声明以仅允许foo
和{{ 1}}互相调用,直到调用该函数,JavaScript才会检查函数中使用的标识符,因此,即使JavaScript没有两个阶段,也不会在C中提出前向声明的某些原因)
这并不是完全成功。在代码中到达bar
语句之前,让var
语句初始化用undefined
声明的变量通常是导致错误和混乱的原因:
var
人们很容易被console.log(answer); // undefined
var answer = 42;
的一半提早完成(var answer = 42;
部分)但另一半({{1 }})直到稍后到达该语句为止。
这就是var answer
和answer = 42;
创建,但是在第一阶段不初始化它们的变量的原因。您可以在声明变量的上方使用变量,但只能在初始化后运行的代码中使用该变量:
let