JavaScript中的“执行上下文”究竟是什么?

我的标题几乎总结了一切。

任何人都可以启发我…

“JavaScript中的'执行上下文'是什么?

以及它如何与“这个”挂钩,原型链接,范围和垃圾收集?

你在问几个不太相近的概念。 我会尽量简单地解决每个问题。


执行上下文是语言规范中的一个概念,用通俗的术语来说,大致上等同于函数执行的“环境” 也就是variables作用域(和作用域链 ,从外部作用域closures的variables),函数参数和this对象的值。

调用堆栈是执行上下文的集合。

另请参阅这个答案和这篇文章 。


范围的字面意思是:variables可以被访问的范围。 简单地:

 var x; function a() { var y; } 

x可以从任何地方访问。 当a被调用时, x将在外部作用域中。 (存储在范围链中

相反, y只能由a()的代码访问,因为它被限制在a范围内。 这是var关键字的作用:将variables限制在本地范围内。 如果我们省略了var ,那么y最终会在全局范围内 ,通常被认为是坏事。


想想更多的是编译时的事情。 在JavaScript中,函数声明被“悬挂”到其范围的顶部。 换句话说,它们是任何其他代码之前被parsing和评估的。 (这与函数expression式是相反的,这些函数expression式是内联计算的。)考虑以下内容:

 a(); b(); function a() { } var b = function() { } 

a()的调用将成功,因为它的声明被提升到最高; a在程序执行开始之前被自动分配。 对b()的调用将失败,并带有TypeError因为在第4行之前不会定义b

讨论了最相关的主题。

执行上下文是现有代码的包装 ; 其中包含你没有写的代码; 但由JS引擎生成

它包括以下内容 –

  1. 全局对象
  2. '这个'
  3. 外部环境
  4. 你的代码

每次运行.js文件/应用程序时都会创build一个执行上下文。 这个创build阶段的第一步是吊装 。 JS引擎为代码中定义的所有variables和函数保留空间设置内存 。 当你的代码被逐行执行时,这些被访问。

例如:

 b(); console.log(a); var a = "hi!"; function b() { console.log("calling function"); } 

这里, 函数b()variablesa在被定义之前都被访问,但是由于提升控制台不会抛出任何错误。

输出看起来像 – (尝试)

 calling function undefined 

注意函数是如何完全执行的,但是我们没有定义variables。 这是因为对于函数和variables来说, 吊装的执行是不同的。 函数作为一个整体被拾取到内存中,但是对于variables,空间被保留为占位符 ,其值为undefined 。 当引擎逐行执行代码时,实际值将被replace。

我希望这个清除你的概念。

你问了这么多的概念,但是让我们逐一挑选并理解它们。

代码运行的环境是Execution context 它是在您的代码执行时创build的。

由JS Engine创build的Execution Context (Global)包含3个重要的事情:

  1. 全局对象 – window
  2. this特殊对象
  3. 参考外部环境

让我们看一个简单的例子来理解Global Execution Context

 var a = "Hello World"; function b(){ } 

当JS Engine运行以上代码时,它会创build以下执行上下文(如图所示): 全局执行上下文


现在让我们看看JS Engine如何创buildExecution Context (然后我们将挖掘并理解提升):考虑这种情况:

 b(); console.log(a); var a = "Hello World!"; function b(){ console.log("Called b!"); } 

即使稍后声明,我也可以调用函数b() 。 这意味着JS Engine在我的代码执行之前做了一些事情,让我们看看:

JS引擎在执行任何代码时执行以下两个步骤:

创造阶段

  • JS引擎parsing – 运行你的代码, identifies variables & functions由代码创build的identifies variables & functions (将在执行阶段使用)
  • 为variables和函数设置存储空间 – “提升”
  • 提升 – 在你的代码被执行之前,JS Engine设置的内存空间用于代码中使用的Var&Func。 这些variables和函数包含了要执行的任何函数的执行上下文。 JS中的所有variables最初设置为undefined。

执行PHASE:相当简单易懂,

  • 当代码逐行执行时(通过JS interpreeter)它可以访问执行上下文中定义的variables
  • variables赋值在这个阶段完成

无论何时函数调用,都会创build一个新的执行上下文

执行上下文栈:当你调用一个函数时会发生什么:

 function b(){ } function a(){ b(); } a(); 
  • 现在首先创buildGlobal Execution Context (如上所述)

  • 然后执行开始和interpreeter遇到call to function a()here a new execution context is created pushed on top EC Stack

    所以无论何时您调用一个函数,都会创build一个新的EC,并放置在EC堆栈上。

  • 所以现在EC for a()CREATED interpreeter会一行一行地执行a()的代码

  • 然后intrepreeter遇到call to function b() ,这将创build另一个EC顶部或EC堆栈上

  • b()完成后,它将popup堆栈,然后a()将完成并一路下降到Global EC

请参阅上述代码片段的执行堆栈

“执行上下文”是一个包装所有代码的伞,以帮助pipe理它。 这就像一个pipe理任何环境的经理。 由于存在如此多的词汇环境,因为在JavaScript应用程序中,您有很多variables和函数,所以您需要一种pipe理一切的方法。 什么是第一个,什么是第二个等等,如果你没有“执行上下文”环境,一切都会下地狱。 所以考虑“执行上下文”一个包装,一个pipe理你的代码的经理。

我想一个简单的例子可以解释一切。

注意: function.call(object)object上下文中调用函数function

 // HTML ​<p id="p"></p>​​​​​​​​​​​​​​​​​​​​​​​​ // JavaScript function helloWorld() { alert("HelloWorld: " + this); } var p = document.getElementById("p"); helloWorld(); // HelloWorld: [object DOMWindow] helloWorld.call(window); // HelloWorld: [object DOMWindow] ​​​​​​helloWorld.call("String"); // HelloWorld: String // Note: "toString()" helloWorld.call​​​​(p); // HelloWorld: [object HTMLParagraphElement] helloWorld.call(new Date());​​​​ // HelloWorld: Tue Feb 21 2012 21:45:17 GMT+0100 (Central Europe Standard Time) 

执行上下文是帮助pipe理正在运行的代码的包装在代码中,您会看到很多词法环境意味着{}之间的代码区域,但是当前运行的代码区域是通过执行上下文进行pipe理的。它可以包含您的代码,也可以包含超出您在代码中所写的内容。