So, what is an execution context ?
We can imagine execution context as a big box with two components in it:
- Memory component / Variable environment: This is the place where memory is allocated to all the variables and functions.
- Code component / Thread of execution: This is the place where code execution takes place synchronously.
Let’s understand it better by taking an example.
Consider the below code as a test code:
When we execute this code, the execution context is created. The creation of execution context is a two step process.
a, b, output with a special value which is
undefined . In case of functions, it stores the whole code attached to the function name.
variable a is assigned a value 10 and similarly
variable b is assigned with value 20, so it updates the respective variables with their values. Next it moves to line 7, where it finds a function (declaration / statement) that has already been allocated with memory during step 1, so it moves ahead to line 11.
Now on line number 11, it invokes the function
aFunctionToCall with values of
a, b as arguments. Whenever a function invocation takes place, a new execution context is created. Now the same process happens with the new execution context, i.e memory allocation followed by code execution.
- Memory is allocated for variables
x, y, sumand are assigned with undefined.
- Code execution — Variables
x, yare assigned with values 10, 20 received as parameters. Sum of
yis calculated and assigned to a variable
sumwhich is then returned.
Once the code inside the function is completely executed and it encounters a return statement, the control is sent back to the parent execution context which had called it and the child execution context (
AFunctionToCall in the image above) pops out and gets deleted from the call stack*.
Now the control is back to line 11 and the returned value is assigned to variable output. Once the whole code is executed, the global execution context, which is the very first execution context, also gets popped out and the call stack is empty.
* You must be wondering what a call stack is ?
If a new function is invoked, its execution context is pushed into the stack and once the scope of the function is finished, it pops out and gets deleted from the call stack. Once the completed program is executed, the global execution context also pops out and gets deleted, making the call stack empty.
Now let’s take another example with closures to understand how execution context works.
aNumber, aVariableMultiplyBy2, aOutput get assigned to
undefined while memory is allocated to function
aFunctionMultiply with its whole code attached to it.
aNumber is assigned with value 2. Next it moves to line 6 where it will see a function (declaration / statement), so it moves ahead to line 11 where a function
aFunctionMultiply is invoked with argument
aNumber with value 2.
x is assigned with value 2 and the function along with its lexical scope
this gets returned.
We can see in the above code snapshot that the execution context for function
aFunctionMultiply is created and has variable
x assigned with 2. Line 7 has a return statement so function
aFunctionReturned along with its lexical scope
this is returned ( which forms a closure).
You must be thinking what is Lexical scope
Lexical scope means that in a nested group of functions, the inner functions have access to the variables and other resources of their parent scope. This means that the child’s functions are lexically bound to the execution context of their parents.
aMultiplyBy2 and execution context for function
aFunctionMultiply pops out and gets deleted as discussed earlier.
aMultiplyBy2 which has a function definition gets invoked. Execution context for it gets created.
You must be wondering how
aFunctionReturned will access value
x inside execution context of
aMultiplyBy2 forms closure with
As we know when a function is returned, function along with its lexical scope gets returned. When a function cannot find any variable inside its scope, it searches its parent’s scope for the same.
As we know, variable
aMultiplyBy2 has function definition of
aFunctionReturned stored in it. Because of closure, it gets value of
aFunctionMultiply and multiplication is done.