Scope
Scope is the accessibility of variables, functions, and objects in some particular part of your code in runtime. In javascript there are two types of scopes: global scope and local scope. Variables defined outside of any function are in global scope while variables defined inside a function are in local scope. When a function is invoked, a new scope is created. But block statements like if
, for
, switch
and while
, don’t create a new scope. Variables defined inside of a block statement will remain in its global or local scope.
Context
Context is always the value of the this
keyword which is a reference to the object that “owns” the currently executing code. As comparison, context refers to this
while scope refers to the visibility of variables in the same function invocation. Inside a function, context (this
) refers to the object which call the function, e.g. in global scope context is the window
object.
Execution context
The term execution context
is defined in javascript specification. Javascript is a single-threaded language so it can only execute a single task at a time. Javascript interpreter maintains an execution stack (frames stack), where there is always only one execution context on the top of it. When javascript interpreter starts to execute your code, it enters into a global execution context by default. The global execution context is pushed to the execution stack. After that, each function invocation will create a new execution context, which is also pushed to execution stack too, so there is always one execution on the top of the execution stack, which is the current execution context. After the function is complete, its execution context is popped out of the stack and then destroyed. To have a more insight of the relationship of context, scope (scope chain) and execution context, we discuss the lifecycle of an execution context in detail.
The execution context has two phases: creation phase and execution phase.
Creation phase is present when a function is called. There are three main actions during the creation phase:
- create the Variable (Activation) Object
- create the Scope Chain
- set the value of context
Variable (Activation) Object contains all of the variables, functions and other declarations defined inside of the execution context. When the function is called, the interpreter scans it for all resources including function arguments, variables, and other declarations. Then the interpreter records them in the Variable Object.
Scope Chain is used to resolve variables, which contains the Variable Object itself. It’s created after the variable object. When asked to resolve a variable (get or set variable value), javascript starts at the innermost level of the function scope (namely the current scope) and keeps jumping back to the parent scope until it finds the variable. The scope chain can simply be defined as an object containing the variable object and its parents’ variable object.
The third step is to set the context value, which means that what this
should be.
Therefore, the execution context object can be represented as:
executionContextObject = {
variableObject: {}, // contains function arguments, inner variables and function declarations
scopeChain: {}, // contains its own variable object and other variable object of parents' execution context
this: valueOfThis
}
Lexical scope
“Lexical” describes how the javascript engine resolve variable names when functions are nested. In a nested group of functions, the inner functions have access to the variables and other resources declared in outer functions(or scopes). In other words, the inner functions are lexically bound to outer scopes.
Closure
The concept of closure is closely related to Lexical scope. A closure is created when an inner function tries to access the scope chain of its outer function meaning the variables outside of the immediate lexical scope. Closure contain its own scope chain, scope chain of its parents till the global scope.
When you return an inner function, that returned function will not be executed when you call the outer function. But the execution context is not destroyed after the outer function is executed, because the returned function keeps execution context of the outer function (though it has been popped out from the execution stack). So the outer function execution context remains in the memory until the no references pointed to returned function. In other words, closure is another way (like new
) to extend the life cycle of the function scope.
Apply() and call()
Apply() and call() functions are used to change the context (namely this
) when calling a function.