You're asking about several different concepts that aren't very closely related. I'll try to briefly address each.
Execution context is a concept in the language spec that—in layman's terms—roughly equates to the 'environment' a function executes in; that is, variable scope (and the scope chain, variables in closures from outer scopes), function arguments, and the value of the this
object.
The call stack is a collection of execution contexts.
See also this answer and this article.
Scope is literally that: the scope in which a variable can be accessed. Simplistically:
var x;
function a() {
var y;
}
x
can be accessed from anywhere. When a
is invoked, x
will be in the outer scope. (Stored in the scope chain.)
In contrast, y
can only be accessed by code in a()
because it is limited to a
's scope. This is what the var
keyword does: restricts a variable to the local scope. If we omitted var
, y
would end up in the global scope, generally considered a bad thing.
Think of hoisting as more of a compile-time thing. In JavaScript, function declarations are "hoisted" to the top of their scope. In other words, they are parsed and evaluated before any other code. (This is opposed to function expressions, which are evaluated inline.) Consider the following:
a();
b();
function a() { }
var b = function() { }
The call to a()
will succeed because its declaration was hoisted to the top; a
was assigned to automatically before program execution began. The call to b()
will fail with a TypeError
because b
will not be defined until line 4.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…