我的头衔几乎概括了这一切。
谁能启发我...
“ JavaScript中的“执行上下文”是什么?”
以及它与“ this”,吊装,原型链,作用域和垃圾收集之间的关系?
Answers:
您要问的是几个密切相关的不同概念。我将尝试简要地解决每个问题。
执行上下文是语言规范中的一个概念,以通俗易懂的术语来说,大致等同于函数执行的“环境”。也就是说,变量作用域(以及作用域链,外部作用域的闭包中的变量),函数参数和this对象的值。
该调用堆栈是执行上下文的集合。
范围从字面上看是:可以访问变量的范围。简单地说:
var x;
function a() {
var y;
}
x可以从任何地方访问。何时a调用,x将在外部范围内。(存储在范围链中。)
相反,y只能由代码访问,a()因为它限于a的范围。这是什么var关键词呢:限制在局部范围的变量。如果我们省略var,y将最终出现在全局范围内,通常被认为是一件坏事。
将提升视为更多的编译时事物。在JavaScript中,函数声明“悬挂”在其作用域的顶部。换句话说,它们是在任何其他代码之前进行解析和评估的。(这与内联求值的函数表达式相反。)请考虑以下几点:
a();
b();
function a() { }
var b = function() { }
对to的调用a()将成功,因为其声明已被置于最高位置;a在程序开始执行之前被自动分配给。到的调用b()将失败,TypeError因为b直到第4行才会定义。
b变量声明也将被吊起:将从一开始就声明它,但是在第4b()行之前不会给它赋值。在第4行之前调用确实会导致错误,但是不同的是:我们将尝试执行undefined,这不是一个函数。
parsing只是我们的JS代码所经历的一部分。而还有其他组成编译动作的部分-Lexer,解析器,语义分析,优化器,代码生成器。最好从改变语义parsing来compiling 参考: stackoverflow.com/questions/1921474/...。
您问了很多概念,但让我们一个接一个地了解它们。
运行代码的环境是Execution context。
它是在执行代码时创建的。
Execution Context (Global),由JS Engine创建,其中包含3个重要的内容:
window this让我们看一个简单的例子来理解Global Execution Context:
var a = "Hello World";
function b(){
}
当JS Engine运行以上代码时,它将创建以下执行上下文(如图所示): 全局执行上下文
现在,让我们看看JS Engine是如何创建的Execution Context(然后我们将挖掘并了解提升):考虑以下情况:
b();
console.log(a);
var a = "Hello World!";
function b(){
console.log("Called b!");
}
b()即使稍后声明,我也可以调用该函数。这意味着JS Engine在执行我的代码之前正在做一些事情,让我们看一下:
JS引擎在执行任何代码时执行以下两个步骤:
创作阶段:
identifies variables & functions并由代码创建(将在执行阶段使用)执行阶段:非常简单易懂,
只要存在函数调用,就会创建一个新的执行上下文。
执行上下文堆栈: 调用函数时会发生什么:
function b(){
}
function a(){
b();
}
a();
现在首先Global Execution Context要创建(如上所述)
然后执行开始,口译员遇到call to function
a(),并且here a new execution context is created pushed on top EC
Stack
因此,无论何时调用函数,都会创建一个新的EC并将其放置在EC Stack的顶部。
所以现在EC for a()是CREATEDinterpreeter将执行里面的代码a()行由行
然后口译员遇到call to function b(),这将创建另一个EC推到顶部或EC堆栈的对象
当b()完成将弹出的出栈,然后a()将完成与一路下跌至Global EC
我只讨论了最密切相关的主题。
执行上下文是您现有代码的包装;其中包含您尚未编写的代码; 但由JS引擎生成。
它包括以下内容-
每次您运行.js文件/应用程序时,都会创建一个执行上下文。此创建阶段的第一步是提升。JS引擎保留空间或集的内存中定义的所有变量和函数的代码。然后在逐行执行代码时访问它们。
例如:
b();
console.log(a);
var a = "hi!";
function b() {
console.log("calling function");
}
在这里,函数b()和变量a都在定义它们之前被访问,但是,由于提升控制台不会引发任何错误。
输出看起来像-(尝试)
calling function
undefined
请注意,函数是如何完全执行的,但尚未为变量定义。这是因为功能和变量的提升方式不同。该函数作为一个整体被吸收到内存中,但是对于变量,将保留空间作为占位符,其值为undefined。当引擎执行的实际值再换成你的代码行由行。
我希望这可以为您清除概念。
我想解决
1:执行上下文
JavaScript是一种单线程语言,意味着一次只能执行一个任务。当JavaScript解释器最初执行代码时,默认情况下它首先进入全局执行上下文。从此以后,每次调用函数都会导致创建新的执行上下文。
这就是经常引起混乱的地方,术语执行上下文实际上在所有意图和目的上都更多地是指范围而不是上下文。这是一个不幸的命名约定,但是它是ECMAScript规范所定义的术语,因此我们对此有些犹豫。
每次创建新的执行上下文时,都会将其附加到执行堆栈的顶部。浏览器将始终执行位于执行堆栈顶部的当前执行上下文。完成后,将从堆栈顶部删除它,并且控件将返回到下面的执行上下文。
执行上下文可以分为创建和执行阶段。在创建阶段,解释器将首先创建一个变量对象(也称为激活对象),该对象由执行上下文中定义的所有变量,函数声明和参数组成。然后从那里初始化作用域链,最后确定它的值。然后在执行阶段,对代码进行解释和执行。
2:此上下文
什么是“此”上下文?上下文通常由函数的调用方式决定。当将函数作为对象的方法调用时,会将其设置为调用该方法的对象:
var obj = {
foo: function() {
return this;
}
};
obj.foo() === obj; // true
使用new运算符调用函数以创建对象的实例时,适用相同的原理。以这种方式调用时,在函数范围内的this值将设置为新创建的实例:
function foo() {
alert(this);
}
foo() // window
new foo() // foo
当作为未绑定函数调用时,它将默认为浏览器中的全局上下文或窗口对象。但是,如果函数在严格模式下执行,则上下文默认为未定义。
3:可变范围
可以在局部或全局范围内定义变量,从而在运行时从不同范围建立变量的可访问性。任何已定义的全局变量,意味着在函数体外部声明的任何变量都将在整个运行时运行,并且可以在任何范围内进行访问和更改。局部变量仅存在于定义它们的函数体内,并且对于该函数的每次调用将具有不同的范围。在那里,仅在该调用内可以进行值分配,检索和操作,而在该范围之外无法访问。
ECMAScript 6(ES6 / ES2015)引入了let和const关键字,这些关键字支持声明块范围局部变量。这意味着该变量将被限制在其定义的块的范围内,例如if语句或for循环,并且在该块的左花括号和右花括号之外将无法访问该变量。这与var声明相反,在声明它们的外部块中可以访问var声明。let和const之间的区别在于,顾名思义,const声明是常量-对值的只读引用。这并不意味着该值是不变的,只是不能重新分配变量标识符。
当您执行一个函数时,您将创建一个execution context包含称为avariable environment且this是占位符的本地内存的新函数,它将在其执行上下文中引用.被调用该函数的位置的左侧。
JS中的EC(执行上下文)是什么?
简而言之,执行上下文是评估和执行Javascript代码的环境的抽象概念。每当任何代码在JavaScript中运行时,它都会在执行上下文中运行。
有关更多详细信息,请参见:https : //blog.bitsrc.io/understanding-execution-context-and-execution-stack-in-javascript-1c9ea8642dd0
我想一个简单的例子可以解释一切。
注意:在以下情况下function.call(object)调用函数functionobject
// 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)