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引擎生成。
它包括以下内容 –
- 全局对象
- '这个'
- 外部环境
- 你的代码
每次运行.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个重要的事情:
- 全局对象 –
window
-
this
特殊对象 - 参考外部环境
让我们看一个简单的例子来理解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();
-
现在首先创build
Global 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理的。它可以包含您的代码,也可以包含超出您在代码中所写的内容。