JavaScript is a single threaded language means code execution happens each line at a time. One of the most famous javascript engine is the v8 engine that is used in chrome. We will see in brief how javascript engine works.
Every browser has a javascript engine which runs the code. As a refresher let’s discuss the stages of javascript execution.
Parser
First of all parser goes through each and every line of code and checks for any syntax errors. After parsing everything parser will create an abstract syntax tree(AST). This helps in representing the code in a much more structured way. Let us see a sample AST for below code snippet.
function func1(y) {
if (y > 2)
var w = 10; }
return y;
This is a simplified version of what the parser will produce. An AST is the result of parsing of the code. After creating the AST the code is converted to machine code and then execution of code happens. Everything in javascript happens within an execution context.
Execution Context
An Execution context is basically the environment in which each line of code gets executed. It is created in 2 phases
Memory Creation Phase — In this phase memory is allocated to all functions and variable without actually executing them. The JS engine runs through the code and will identify variable and functions which will be used in execution phase. All the variables will initially be set to undefined. Hoisting also takes place in this phase. We will look at hoisting bit later.
Code execution phase — In this phase each line of code is executed. The variables are assigned to their respective values.
Hoisting — The JS engine reserves memory for all variables and functions defined in the code.Javascript moves all the declarations to the top of current scope. This means that a variable can be used before it has been declared. Let us see this with help of an example
func1(); console.log(key);
var key = "Hello World";
function func1() {
console.log("Inside func1 function"); }
// Output
// Inside func1 function
// undefined
Here the function func1 and variable key are accessed before they are defined but because of hosting no error is thrown. The function gets executed completely but the variable key is printed as undefined. This happens because of the way in which hoisting takes place for variables and functions is different. The variables are initially set to undefined and in case of functions their whole code is picked into the memory. Lets see one more example of hoisting
console.log(x); // undefined x = 10; console.log(10); // 10var x;
Initially undefined is printed as variable x will be declared and moved to top of current scope but no value has yet been assigned so javascript assigns it to undefined. Once the assignment has taken place it prints 10. And yes, this is again the power of hoisting that allows us to access variables even before it has been declared.
There are 2 types of execution context:
Global Execution context — Everything in our program happens within the global execution context.This gets created by javascript by default before it starts executing any code.The global execution context creates 2 things: - A window object. This is the global object when javascript runs. - A this variable. In global execution context this variable equals the global window object.
console.log(this == window); // prints the value as true
This means that all variables that are declared outside of any functions will be attached to the window object and can be referenced by using this.
var keyword = 'test';
console.log(keyword);
console.log(this.keyword); console.log(window.keyword);
//Above all 3 statements will print same content that is 'test'
2. Function Execution context — Whenever a function is executed a separate execution context is created for each function. Any variable declared inside a function will be part of that respective functional context but not of global execution context.
Execution Stack
This is a normal stack with LIFO(Last in first out) order and stores all the execution contexts that were created during code execution. Initially a global execution context is pushed into the stack.
Whenever a new function invocation is there a new execution context is created for that function and pushed to top of stack. The function whose execution context is at top of the stack is executed first and after execution ,its execution context is popped off from the stack and control goes to the context below it.
Let us see this with help of an example
function func1() { func2(); console.log("Inside first function"); } function func2() { console.log("Inside second function"); } func1();
// Output
/
/Inside second function
// Inside first function
The stack trace for above code will be like below:
Step 1 — Initially the global execution context will be pushed into the stack.
Step 2 — As soon as func1 is triggered a separate execution context is pushed into the stack.
Step 3 — Then func2 is triggered and new execution context is created for it.
Step 4 — After func2 is executed it gets popped of from the stack the control returns back to func1.
Step 5 — After func1 is executed it gets popped off from stack.
When all the code is executed the global execution context is popped off the stack and execution of javascript ends.
References
Also, read our blog on The New Age of Javascript
Comentários