有时我读“调用上下文”,有时读“执行上下文”。我想知道我们是否在谈论相同的概念。
我必须说,在 ECMAScript6 规范中,我没有找到任何对“调用上下文”的引用。
有时我读“调用上下文”,有时读“执行上下文”。我想知道我们是否在谈论相同的概念。
我必须说,在 ECMAScript6 规范中,我没有找到任何对“调用上下文”的引用。
简而言之,他们定义了scope与context。范围是关于代码运行的环境(有点像一个房间——它是关于代码所在的位置),而上下文是关于一个导致一些代码被执行的实际对象(比如谁负责把你放在那个房间里) .
“执行上下文”指的是在某些代码运行时生效的“作用域链”。作用域链是一个内存位置列表,应该检查(按特定顺序)以查找要解析为值的标识符(变量、常量和函数名称)。由于 JavaScript 是在单线程环境中执行的,因此一次只能执行一个任务。当前正在执行的代码(及其关联的范围)定义了执行上下文。
一个简单的例子可以像这样显示:
// This area is in the Global execution context (scope) because the code is
// not wrapped in a function or any other kind of code block.
var x = "Global";
// "Global" is the result because the JavaScript engine will always look
// in the current scope for a declaration for the identifier in question.
// It will find a declaration for "x" right here in the Global scope, so
// that's the value it will use.
console.log(x);
var y = "Also Global";
function parent(){
// This area is in the "parent" execution context (scope)
var x = "parent";
// "parent" is the result (not "Global") because when this function is
// executing, its scope is the most accessible. The JavaScript engine
// looks here first to find out what "x" is. This is known as variable
// "hiding" because the x in the parent scope hides the x in the Global scope.
console.log(x);
function child() {
// This area is in the "child" execution context (scope)
var x = "child";
// "child" is the result (not "Global" or "parent") because when this
// function is executing, its scope is the most accessible. The
// JavaScript engine looks here first to find out what "x" is. This
// x now hides the x in parent, which is hiding the x in Global.
console.log(x);
// "Also Global" is the result here. First the current execution
// context (scope) is checked for a "y" variable. There isn't one,
// so the next scope in the scope chain (function parent) is checked.
// There is no "y" declared there either. So, again, the next highest
// scope in the chain (Global) is checked and that is where "y" is
// found, so the value of that "y" is used.
console.log(y);
// Here, we will get "undefined". All the scopes in the chain will
// be checked and if we go all the way up to Global and still don't
// find a declaration for "z", there is no other scope to look in.
console.log(z);
}
child();
}
parent();
上面显示的三个执行上下文(范围)可以通过多种方式进入。这些不同的方式产生了“调用上下文”。
“调用上下文”也可以更准确地称为“调用上下文对象”,它指的是用于调用某些代码的对象。这可能看起来与“执行上下文”相同,但“调用上下文”指的是导致代码执行的 对象,并且正在执行的代码在其自己的执行上下文(范围)内执行此操作。
这两个术语之间最大的区别是理解调用上下文导致关键字this
在执行上下文期间绑定到对象。this
绑定在 JavaScript 中是不稳定的,this
绑定到的对象在您进入新的执行上下文时会发生变化。对于所有意图和目的,this
是调用某些代码的对象,还是this
“调用上下文”。
我写了另一个答案,其中详细介绍了如何确定this
将绑定到的内容,您可以在此处查看。
有关调用上下文的说明,请参阅以下代码段。它说明了一个 执行上下文( function foo
),但说明了两个 调用上下文(按钮和全局)。
function foo() {
// When this function is "invoked" via the button click
// the invocation context is the button and the console will
// log this as: [object HTMLButtonElement]
// But, when the function is invoked from a direct call to foo
// from the Global execution context, this will be bound
// to the window object. So, in that case we'll get: [object Window]
console.log("The 'this' object (invocation context object) is: " + this);
}
// Call foo from the Global execution context.
foo();
var btn = document.getElementById("btnTest");
// When the button is clicked, execute foo
btn.addEventListener("click", foo);
<button id="btnTest">Click Me</button>