我的头衔几乎总结了一切.
任何人都可以启发我...
"JavaScript中的'执行上下文'是什么?"
以及它如何与'this',吊装,原型链,范围和垃圾收集有关?
jos*_*736 52
你问的是几个不太密切相关的不同概念.我将尝试简要地解决每个问题.
执行上下文是语言规范中的一个概念 - 在外行人的术语中 - 大致等同于一个函数执行的'环境'; 也就是说,变量作用域(以及作用域链,来自外部作用域的闭包中的变量),函数参数和this对象的值.
该调用堆栈是执行上下文的集合.
范围实际上是:可以访问变量的范围.简单地:
var x;
function a() {
var y;
}
Run Code Online (Sandbox Code Playgroud)
x可以从任何地方访问.何时a被调用,x将在外部范围内.(存储在范围链中.)
相反,y只能通过代码访问,a()因为它仅限于a范围.这就是var关键字的作用:将变量限制为本地范围.如果我们省略var,y最终将在全球范围内,通常被认为是一件坏事.
想想吊装更多的编译时的事情.在JavaScript中,函数声明被"提升"到其作用域的顶部.换句话说,它们在任何其他代码之前被解析和评估.(这与函数表达式相反,函数表达式是内联计算的.)请考虑以下事项:
a();
b();
function a() { }
var b = function() { }
Run Code Online (Sandbox Code Playgroud)
呼吁a()将成功,因为它的声明被提升到顶部; a在程序执行开始之前自动分配.调用b()将失败,TypeError因为b在第4行之前不会定义.
我想解决
\n\n1:执行上下文
\n\nJavaScript 是一种单线程语言,这意味着一次只能执行一个任务。当 JavaScript 解释器最初执行代码时,它首先默认进入全局执行上下文。从此时起,每次调用函数都将创建一个新的执行上下文。
\n\n这就是经常引起混淆的地方,术语“执行上下文”实际上是为了所有意图和目的而更多地指范围而不是上下文。这是一个不幸的命名约定,但它是 ECMAScript 规范定义的术语,所以我们\xe2\x80\x99 有点坚持它。
\n\n每次创建新的执行上下文时,都会将其附加到执行堆栈的顶部。浏览器将始终执行位于执行堆栈顶部的当前执行上下文。一旦完成,它将被从堆栈顶部移除,控制权将返回到下面的执行上下文。
\n\n执行上下文可以分为创建阶段和执行阶段。在创建阶段,解释器将首先创建一个变量对象(也称为激活对象),该对象由执行上下文中定义的所有变量、函数声明和参数组成。从那里开始,接下来初始化作用域链,最后确定它的值。然后在执行阶段,代码被解释并执行。
\n\n2:这个上下文
\n\n\xe2\x80\x9cthis\xe2\x80\x9d 上下文是什么?\n上下文通常由函数的调用方式决定。当函数作为对象的方法被调用时,this 被设置为调用该方法的对象:
\n\nvar obj = {\n foo: function() {\n return this; \n }\n};\n\nobj.foo() === obj; // true\nRun Code Online (Sandbox Code Playgroud)\n\n当使用 new 运算符调用函数来创建对象的实例时,同样的原则也适用。当以这种方式调用时,函数范围内的 this 值将被设置为新创建的实例:
\n\nfunction foo() {\n alert(this);\n}\n\nfoo() // window\nnew foo() // foo\nRun Code Online (Sandbox Code Playgroud)\n\n当作为未绑定函数调用时,这将默认为浏览器中的全局上下文或窗口对象。但是,如果函数在严格模式下执行,上下文将默认为未定义。
\n\n3:变量范围
\n\n变量可以在本地作用域或全局作用域中定义,这会在运行时从不同作用域建立变量\xe2\x80\x99 可访问性。任何定义的全局变量,意味着在函数体外部声明的任何变量都将在整个运行时存在,并且可以在任何范围内访问和更改。局部变量仅存在于定义它们的函数体内,并且对于该函数的每次调用都有不同的作用域。在那里,它仅在该调用内进行值分配、检索和操作,并且在该范围之外不可访问。
\n\nECMAScript 6 (ES6/ES2015) 引入了let 和 const关键字,支持块作用域局部变量的声明。这意味着变量将被限制在定义它的块的范围内,例如 if 语句或 for 循环,并且在块的左大括号和右大括号之外将无法访问。这与 var 声明相反,var 声明可以在定义它们的块之外访问。let 和 const 之间的区别在于,const 声明,顾名思义,是常量 - 对值的只读引用。这并不意味着该值是不可变的,只是变量标识符不能被重新分配。
\n\n对于其他主题: \nGC : GC \n原型制作 :原型制作
\n小智 8
你问过这么多概念,但我们一个接一个地挑选并理解它们.
代码运行的环境是Execution context.
它是在执行代码时创建的.
Execution Context (Global),由JS Engine创建,包含3个重要的事项:
window this让我们看一个简单的例子来理解Global Execution Context:
var a = "Hello World";
function b(){
}
Run Code Online (Sandbox Code Playgroud)
当JS Engine运行上面的代码时,它会创建以下执行上下文(如图所示): 全局执行上下文
现在让我们看看JS Engine如何创建Execution Context(然后我们将挖掘并理解提升):考虑这种情况:
b();
console.log(a);
var a = "Hello World!";
function b(){
console.log("Called b!");
}
Run Code Online (Sandbox Code Playgroud)
b()即使稍后声明,我也可以调用该函数.这意味着JS Engine在我的代码执行之前正在做一些事情,让我们看看:
JS Engine在执行任何代码时执行以下两个步骤:
创作阶段:
identifies variables & functions通过代码创建(将在执行阶段使用)执行阶段:很容易理解,
只要存在函数调用,就会创建一个新的执行上下文
执行上下文堆栈: 调用函数时会发生什么:
function b(){
}
function a(){
b();
}
a();
Run Code Online (Sandbox Code Playgroud)
现在首先Global Execution Context要创建(如上所述)
然后执行开始和interpreeter遇到call to function
a(),和here a new execution context is created pushed on top EC
Stack
因此,只要您调用一个函数,就会创建一个新的EC并将其置于EC Stack之上.
所以现在EC for a()是CREATEDinterpreeter将a()逐行执行代码
然后是intrepreeter遭遇call to function b(),这会创建另一个EC被推到顶部或EC堆栈
当b()完成将弹出的出栈,然后a()将完成与一路下跌至Global EC
小智 6
我只讨论了最密切相关的主题。
执行上下文是现有代码的包装器;其中包含您尚未编写的代码;但由JS 引擎生成。
它包括以下内容——
每次运行 .js 文件/应用程序时都会创建一个执行上下文。这个创建阶段的第一步是提升。JS引擎保留空间或集的内存中定义的所有变量和函数的代码。当您的代码逐行执行时,这些将被访问。
例如:
b();
console.log(a);
var a = "hi!";
function b() {
console.log("calling function");
}
Run Code Online (Sandbox Code Playgroud)
这里,函数 b()和变量 a都在定义之前被访问,但是,由于提升控制台不会抛出任何错误。
输出看起来像 - (试试看)
calling function
undefined
Run Code Online (Sandbox Code Playgroud)
注意函数是如何完全执行的,但是我们没有为变量定义。这是因为函数和变量的提升执行方式不同。函数作为一个整体被提取到内存中,但对于变量,空间被保留作为占位符,其值为undefined。当引擎逐行执行您的代码时,实际值将被替换。
我希望这可以为您清除概念。
| 归档时间: |
|
| 查看次数: |
26156 次 |
| 最近记录: |