Execution Context
An execution context is the environment the engine creates to run a piece of
code: the global code, a module, or a single function call. It keeps track of
which variables are visible (the lexical environment) and what this
is. Contexts live on the call stack: calling a function pushes a new
context, returning from it pops the context.
Details
Types
- Global: one per script, created before any code runs. Top-level
varand function declarations become properties of the global object;let,constandclassdo not. - Function: a new one for every call, not for every function.
- Module: each ES module has its own. Top-level
thisisundefinedand declarations are not global. - Eval: for code passed to
eval(). Rarely relevant.
What a Context Holds
- Environment records that store the identifiers:
LexicalEnvironmentforlet,const,classand block scopes;VariableEnvironmentforvarand function declarations.
- A reference from each environment to its outer environment. This is the scope chain.
- The
thisbinding. Seethis.
Variable Object and Activation Object are the ES3 names for the same idea. Since ES5 the specification uses environment records.
Two Phases
- Creation. Before any line runs, the engine registers all declarations of
the scope:
- function declarations are ready to call;
varvariables are set toundefined;let,constandclassexist but are uninitialized (the temporal dead zone).
- Execution. The code runs line by line and assignments happen.
The creation phase is what is called hoisting. Nothing is moved in the code. See Variables.
Scope Chain
To resolve a name, the engine looks in the current environment, then in the
outer one, and so on up to the global environment. If the name is not found, it
throws a ReferenceError.
The outer environment is the place where the function was defined, not where it was called. This is lexical scope, and it is what makes closures work.
Example
Creation phase:
console.log(a); // undefined
console.log(typeof f); // 'function'
console.log(b); // ReferenceError: Cannot access 'b' before initialization
var a = 1;
let b = 2;
function f() {}
Lexical scope:
const x = 'global';
function show() {
console.log(x);
}
function run() {
const x = 'local';
show();
}
run(); // 'global'
Follow-up Questions
- What is the call stack? The stack of execution contexts. Recursion without an
exit overflows it:
RangeError: Maximum call stack size exceeded. - How is a closure related to the execution context? A function keeps a reference to the environment it was created in, so that environment outlives its context. See Closures.
- What is the difference between scope and context? Scope is about which
variables are visible. In everyday speech "context" usually means the value of
this. - How does asynchronous code get on the stack? See Event Loop.
Common Mistakes
- "Declarations are moved to the top of the scope." They are registered during the creation phase; the code is not rearranged.
- "A context is created for each function." It is created for each call.
- Describing the context through Variable Object and Activation Object. These terms are from ES3.