2. What we will see . . .
● Compilation
● Execution
● Variable shadowing
● Variable hoisting
● Closures
● Execution context stack
● Event loop
3. Compilation Phase
● Creates the variable object: Variable object is a special object in JS which contain all the variables, function arguments and
inner functions declarations information.
● Creates the scope chain
● Determines the value of this
Extracts all the declarations (variable, function). It prepares the memory so that it can execute the code
variableObject: {
argumentObject: { }
},
scopechain: [],
This
4. Execution Phase
JavaScript is a single threaded language, meaning only one task can be executed at a time. When the JavaScript interpreter initially
executes code, it first enters into a global execution context by default. Each invocation of a function from this point on will result in
the creation of a new execution context.
● Global execution context
● Functional execution context
executionContextObj = {
variableObject: {
argumentObject: { }
},
scopechain: [],
this
}
6. 1 let a = 2;
2 b = 1;
3
4 function funcName() {
5 let foo = "foo";
6
7 function funcNameA(arg1) {
8 let foo1 = "foo1";
9
10 let foo2;
11
12 foo3 = "foo3";
13
14 a = 4;
15 }
16
17 foo1 = "foo value";
18 let bar = "bar";
19
20 funcNameA(10);
21 }
22
23 funcName();
globalExecutionContextObj = {
variableObject: {
argumentObject: { }
},
scopechain: [],
this
}
>
7. 1 let a = 2;
2 b = 1;
3
4 function funcName() {
5 let foo = "foo";
6
7 function funcNameA(arg1) {
8 let foo1 = "foo1";
9
10 let foo2;
11
12 foo3 = "foo3";
13
14 a = 4;
15 }
16
17 foo1 = "foo value";
18 let bar = "bar";
19
20 funcNameA(10);
21 }
22
23 funcName();
globalExecutionContextObj = {
variableObject: {
argumentObject: { },
a: undefined
},
scopechain: [],
this
}
>
8. 1 let a = 2;
2 b = 1;
3
4 function funcName() {
5 let foo = "foo";
6
7 function funcNameA(arg1) {
8 let foo1 = "foo1";
9
10 let foo2;
11
12 foo3 = "foo3";
13
14 a = 4;
15 }
16
17 foo1 = "foo value";
18 let bar = "bar";
19
20 funcNameA(10);
21 }
22
23 funcName();
globalExecutionContextObj = {
variableObject: {
argumentObject: { },
a: undefined
},
scopechain: [],
this
}
> no declaration found on this line. The JS engine moves on the next
line
9. 1 let a = 2;
2 b = 1;
3
4 function funcName() {
5 let foo = "foo";
6
7 function funcNameA(arg1) {
8 let foo1 = "foo1";
9
10 let foo2;
11
12 foo3 = "foo3";
13
14 a = 4;
15 }
16
17 foo1 = "foo value";
18 let bar = "bar";
19
20 funcNameA(10);
21 }
22
23 funcName();
globalExecutionContextObj = {
variableObject: {
argumentObject: { },
a: undefined,
funcName: pointer to heap memory in the function definition
},
scopechain: [],
this
}
> Whenever the JS engines finds a function declaration, creates a
property and points to heap memory where the function definition is
stored
> Moves to line 23
10. 1 let a = 2;
2 b = 1;
3
4 function funcName() {
5 let foo = "foo";
6
7 function funcNameA(arg1) {
8 let foo1 = "foo1";
9
10 let foo2;
11
12 foo3 = "foo3";
13
14 a = 4;
15 }
16
17 foo1 = "foo value";
18 let bar = "bar";
19
20 funcNameA(10);
21 }
22
23 funcName();
globalExecutionContextObj = {
variableObject: {
argumentObject: { },
a: undefined,
funcName: pointer to heap memory in the function definition
},
scopechain: [],
this
}
> This is not a declaration. Code won’t do anything here
11. 1 let a = 2;
2 b = 1;
3
4 function funcName() {
5 let foo = "foo";
6
7 function funcNameA(arg1) {
8 let foo1 = "foo1";
9
10 let foo2;
11
12 foo3 = "foo3";
13
14 a = 4;
15 }
16
17 foo1 = "foo value";
18 let bar = "bar";
19
20 funcNameA(10);
21 }
22
23 funcName();
globalExecutionContextObj = {
variableObject: {
argumentObject: {
length: 0
},
a: undefined,
funcName: pointer to heap memory in the function definition
},
scopechain: [Global execution context],
this: value of this
}
> end of code. Hence...
> scopechain is set
> this is set
13. 1 let a = 2;
2 b = 1;
3
4 function funcName() {
5 let foo = "foo";
6
7 function funcNameA(arg1) {
8 let foo1 = "foo1";
9
10 let foo2;
11
12 foo3 = "foo3";
13
14 a = 4;
15 }
16
17 foo1 = "foo value";
18 let bar = "bar";
19
20 funcNameA(10);
21 }
22
23 funcName();
globalExecutionContextObj = {
variableObject: {
argumentObject: {
length: 0
},
a: 2,
funcName: pointer to heap memory in the function definition
},
scopechain: [Global execution context],
this: value of this
}
>
14. 1 let a = 2;
2 b = 1;
3
4 function funcName() {
5 let foo = "foo";
6
7 function funcNameA(arg1) {
8 let foo1 = "foo1";
9
10 let foo2;
11
12 foo3 = "foo3";
13
14 a = 4;
15 }
16
17 foo1 = "foo value";
18 let bar = "bar";
19
20 funcNameA(10);
21 }
22
23 funcName();
globalExecutionContextObj = {
variableObject: {
argumentObject: {
length: 0
},
a: 2,
funcName: pointer to heap memory in the function definition,
b: 1
},
scopechain: [Global execution context],
this: value of this
}
> No property with name b found. JS engine will create it and
initialize it with value 1
15. 1 let a = 2;
2 b = 1;
3
4 function funcName() {
5 let foo = "foo";
6
7 function funcNameA(arg1) {
8 let foo1 = "foo1";
9
10 let foo2;
11
12 foo3 = "foo3";
13
14 a = 4;
15 }
16
17 foo1 = "foo value";
18 let bar = "bar";
19
20 funcNameA(10);
21 }
22
23 funcName();
globalExecutionContextObj = {
variableObject: {
argumentObject: {
length: 0
},
a: 2,
funcName: pointer to heap memory in the function definition,
b: 1
},
scopechain: [Global execution context],
this: value of this
}
> No property with name b found. JS engine will create it and
initialize it with value 1
16. 1 let a = 2;
2 b = 1;
3
4 function funcName() {
5 let foo = "foo";
6
7 function funcNameA(arg1) {
8 let foo1 = "foo1";
9
10 let foo2;
11
12 foo3 = "foo3";
13
14 a = 4;
15 }
16
17 foo1 = "foo value";
18 let bar = "bar";
19
20 funcNameA(10);
21 }
22
23 funcName();
globalExecutionContextObj = {
variableObject: {
argumentObject: {
length: 0
},
a: 2,
funcName: pointer to heap memory in the function definition,
b: 1
},
scopechain: [Global execution context],
this: value of this
}
> Since it’s a function declaration the engine won’t do anything, and
moves to line 23
17. 1 let a = 2;
2 b = 1;
3
4 function funcName() {
5 let foo = "foo";
6
7 function funcNameA(arg1) {
8 let foo1 = "foo1";
9
10 let foo2;
11
12 foo3 = "foo3";
13
14 a = 4;
15 }
16
17 foo1 = "foo value";
18 let bar = "bar";
19
20 funcNameA(10);
21 }
22
23 funcName();
globalExecutionContextObj = {
variableObject: {
argumentObject: {
length: 0
},
a: 2,
funcName: pointer to heap memory in the function definition,
b: 1
},
scopechain: [Global execution context],
this: value of this
}
>
19. 1 let a = 2;
2 b = 1;
3
4 function funcName() {
5 let foo = "foo";
6
7 function funcNameA(arg1) {
8 let foo1 = "foo1";
9
10 let foo2;
11
12 foo3 = "foo3";
13
14 a = 4;
15 }
16
17 foo1 = "foo value";
18 let bar = "bar";
19
20 funcNameA(10);
21 }
22
23 funcName();
funcNameExecutionContextObj = {
variableObject: {
argumentObject: {}
},
scopechain: [],
this:
}
> No arguments specified. Nothing will added in the argumentObject
20. 1 let a = 2;
2 b = 1;
3
4 function funcName() {
5 let foo = "foo";
6
7 function funcNameA(arg1) {
8 let foo1 = "foo1";
9
10 let foo2;
11
12 foo3 = "foo3";
13
14 a = 4;
15 }
16
17 foo1 = "foo value";
18 let bar = "bar";
19
20 funcNameA(10);
21 }
22
23 funcName();
funcNameExecutionContextObj = {
variableObject: {
argumentObject: {},
foo: undefined
},
scopechain: [],
this:
}
>
21. 1 let a = 2;
2 b = 1;
3
4 function funcName() {
5 let foo = "foo";
6
7 function funcNameA(arg1) {
8 let foo1 = "foo1";
9
10 let foo2;
11
12 foo3 = "foo3";
13
14 a = 4;
15 }
16
17 foo1 = "foo value";
18 let bar = "bar";
19
20 funcNameA(10);
21 }
22
23 funcName();
funcNameExecutionContextObj = {
variableObject: {
argumentObject: {},
foo: undefined,
funcNameA: pointer to heap memory in the function definition
},
scopechain: [],
this:
}
>
22. 1 let a = 2;
2 b = 1;
3
4 function funcName() {
5 let foo = "foo";
6
7 function funcNameA(arg1) {
8 let foo1 = "foo1";
9
10 let foo2;
11
12 foo3 = "foo3";
13
14 a = 4;
15 }
16
17 foo1 = "foo value";
18 let bar = "bar";
19
20 funcNameA(10);
21 }
22
23 funcName();
funcNameExecutionContextObj = {
variableObject: {
argumentObject: {},
foo: undefined,
funcNameA: pointer to heap memory in the function definition
},
scopechain: [],
this:
}
> This is not a declaration. Code won’t do anything here
23. 1 let a = 2;
2 b = 1;
3
4 function funcName() {
5 let foo = "foo";
6
7 function funcNameA(arg1) {
8 let foo1 = "foo1";
9
10 let foo2;
11
12 foo3 = "foo3";
13
14 a = 4;
15 }
16
17 foo1 = "foo value";
18 let bar = "bar";
19
20 funcNameA(10);
21 }
22
23 funcName();
funcNameExecutionContextObj = {
variableObject: {
argumentObject: {},
foo: undefined,
funcNameA: pointer to heap memory in the function definition,
bar: undefined
},
scopechain: [],
this:
}
>
24. 1 let a = 2;
2 b = 1;
3
4 function funcName() {
5 let foo = "foo";
6
7 function funcNameA(arg1) {
8 let foo1 = "foo1";
9
10 let foo2;
11
12 foo3 = "foo3";
13
14 a = 4;
15 }
16
17 foo1 = "foo value";
18 let bar = "bar";
19
20 funcNameA(10);
21 }
22
23 funcName();
funcNameExecutionContextObj = {
variableObject: {
argumentObject: {},
foo: undefined,
funcNameA: pointer to heap memory in the function definition,
bar: undefined
},
scopechain: [],
this:
}
> This is not a declaration. Code won’t do anything here
25. 1 let a = 2;
2 b = 1;
3
4 function funcName() {
5 let foo = "foo";
6
7 function funcNameA(arg1) {
8 let foo1 = "foo1";
9
10 let foo2;
11
12 foo3 = "foo3";
13
14 a = 4;
15 }
16
17 foo1 = "foo value";
18 let bar = "bar";
19
20 funcNameA(10);
21 }
22
23 funcName();
funcNameExecutionContextObj = {
variableObject: {
argumentObject: {},
foo: undefined,
funcNameA: pointer to heap memory in the function definition,
bar: undefined
},
scopechain: [funcName execution context, Global execution context],
this: value of this
}
> end of code. Hence...
> scopechain is set
> this is set
>
> As there is no other code, JS engine will start the execution phase
27. 1 let a = 2;
2 b = 1;
3
4 function funcName() {
5 let foo = "foo";
6
7 function funcNameA(arg1) {
8 let foo1 = "foo1";
9
10 let foo2;
11
12 foo3 = "foo3";
13
14 a = 4;
15 }
16
17 foo1 = "foo value";
18 let bar = "bar";
19
20 funcNameA(10);
21 }
22
23 funcName();
funcNameExecutionContextObj = {
variableObject: {
argumentObject: {
length: 0
},
foo: “foo”,
funcNameA: pointer to heap memory in the function definition,
bar: undefined
},
scopechain: [funcName execution context, Global execution context],
this: value of this
}
>
28. funcNameExecutionContextObj = {
variableObject: {
argumentObject: {
length: 0
},
foo: “foo”,
funcNameA: pointer to heap memory in the function definition,
bar: undefined
},
scopechain: [funcName execution context, Global execution context],
this: value of this
}
> It’s a function declaration, JS engine won’t do anything and moves
to line 17
1 let a = 2;
2 b = 1;
3
4 function funcName() {
5 let foo = "foo";
6
7 function funcNameA(arg1) {
8 let foo1 = "foo1";
9
10 let foo2;
11
12 foo3 = "foo3";
13
14 a = 4;
15 }
16
17 foo1 = "foo value";
18 let bar = "bar";
19
20 funcNameA(10);
21 }
22
23 funcName();
29. 1 let a = 2;
2 b = 1;
3
4 function funcName() {
5 let foo = "foo";
6
7 function funcNameA(arg1) {
8 let foo1 = "foo1";
9
10 let foo2;
11
12 foo3 = "foo3";
13
14 a = 4;
15 }
16
17 foo1 = "foo value";
18 let bar = "bar";
19
20 funcNameA(10);
21 }
22
23 funcName();
funcNameExecutionContextObj = {
variableObject: {
argumentObject: {
length: 0
},
foo: “foo”,
funcNameA: pointer to heap memory in the function definition,
bar: undefined
},
scopechain: [funcName execution context, Global execution context],
this: value of this
}
globalExecutionContextObj = {
variableObject: {
argumentObject: {
length: 0
},
a: 2,
funcName: pointer to heap memory in the function definition,
b: 1,
foo1: “foo value”
},
scopechain: [Global execution context],
this: value of this
}
> There is no foo1 variable in the execution context. JS engines asks
the next execution context of the scope chain if this variable
exists. It doesn’t, so it creates it and assign the value
30. 1 let a = 2;
2 b = 1;
3
4 function funcName() {
5 let foo = "foo";
6
7 function funcNameA(arg1) {
8 let foo1 = "foo1";
9
10 let foo2;
11
12 foo3 = "foo3";
13
14 a = 4;
15 }
16
17 foo1 = "foo value";
18 let bar = "bar";
19
20 funcNameA(10);
21 }
22
23 funcName();
funcNameExecutionContextObj = {
variableObject: {
argumentObject: {
length: 0
},
foo: “foo”,
funcNameA: pointer to heap memory in the function definition,
bar: “bar”
},
scopechain: [funcName execution context, Global execution context],
this: value of this
}
>
31. 1 let a = 2;
2 b = 1;
3
4 function funcName() {
5 let foo = "foo";
6
7 function funcNameA(arg1) {
8 let foo1 = "foo1";
9
10 let foo2;
11
12 foo3 = "foo3";
13
14 a = 4;
15 }
16
17 foo1 = "foo value";
18 let bar = "bar";
19
20 funcNameA(10);
21 }
22
23 funcName();
funcNameExecutionContextObj = {
variableObject: {
argumentObject: {
length: 0
},
foo: “foo”,
funcNameA: pointer to heap memory in the function definition,
bar: “bar”
},
scopechain: [funcName execution context, Global execution context],
this: value of this
}
globalExecutionContextObj = {
variableObject: {
argumentObject: {
length: 0
},
a: 2,
funcName: pointer to heap memory in the function definition,
b: 1,
foo1: “foo value”
},
scopechain: [Global execution context],
this: value of this
}
>
33. 1 let a = 2;
2 b = 1;
3
4 function funcName() {
5 let foo = "foo";
6
7 function funcNameA(arg1) {
8 let foo1 = "foo1";
9
10 let foo2;
11
12 foo3 = "foo3";
13
14 a = 4;
15 }
16
17 foo1 = "foo value";
18 let bar = "bar";
19
20 funcNameA(10);
21 }
22
23 funcName();
funcNameAExecutionContextObj = {
variableObject: {
argumentObject: {
0: arg1,
length: 1
},
arg1: 10
},
scopechain: [],
this:
}
> funcNameA has arg1 as variable. JS engine will add the arg1 in the
argument object and will create the property arg1 with value 10 in
the variable object
34. 1 let a = 2;
2 b = 1;
3
4 function funcName() {
5 let foo = "foo";
6
7 function funcNameA(arg1) {
8 let foo1 = "foo1";
9
10 let foo2;
11
12 foo3 = "foo3";
13
14 a = 4;
15 }
16
17 foo1 = "foo value";
18 let bar = "bar";
19
20 funcNameA(10);
21 }
22
23 funcName();
funcNameAExecutionContextObj = {
variableObject: {
argumentObject: {
0: arg1,
length: 1
},
arg1: 10,
foo1: undefined
},
scopechain: [],
this:
}
> Variable shadowing
35. 1 let a = 2;
2 b = 1;
3
4 function funcName() {
5 let foo = "foo";
6
7 function funcNameA(arg1) {
8 let foo1 = "foo1";
9
10 let foo2;
11
12 foo3 = "foo3";
13
14 a = 4;
15 }
16
17 foo1 = "foo value";
18 let bar = "bar";
19
20 funcNameA(10);
21 }
22
23 funcName();
funcNameAExecutionContextObj = {
variableObject: {
argumentObject: {
0: arg1,
length: 1
},
arg1: 10,
foo1: undefined,
foo2: undefined
},
scopechain: [],
this:
}
>
36. 1 let a = 2;
2 b = 1;
3
4 function funcName() {
5 let foo = "foo";
6
7 function funcNameA(arg1) {
8 let foo1 = "foo1";
9
10 let foo2;
11
12 foo3 = "foo3";
13
14 a = 4;
15 }
16
17 foo1 = "foo value";
18 let bar = "bar";
19
20 funcNameA(10);
21 }
22
23 funcName();
funcNameAExecutionContextObj = {
variableObject: {
argumentObject: {
0: arg1,
length: 1
},
arg1: 10,
foo1: undefined,
foo2: undefined
},
scopechain: [],
this:
}
> This is not a declaration. Code won’t do anything here
37. 1 let a = 2;
2 b = 1;
3
4 function funcName() {
5 let foo = "foo";
6
7 function funcNameA(arg1) {
8 let foo1 = "foo1";
9
10 let foo2;
11
12 foo3 = "foo3";
13
14 a = 4;
15 }
16
17 foo1 = "foo value";
18 let bar = "bar";
19
20 funcNameA(10);
21 }
22
23 funcName();
funcNameAExecutionContextObj = {
variableObject: {
argumentObject: {
0: arg1,
length: 1
},
arg1: 10,
foo1: undefined,
foo2: undefined
},
scopechain: [],
this:
}
> This is not a declaration. Code won’t do anything here
38. 1 let a = 2;
2 b = 1;
3
4 function funcName() {
5 let foo = "foo";
6
7 function funcNameA(arg1) {
8 let foo1 = "foo1";
9
10 let foo2;
11
12 foo3 = "foo3";
13
14 a = 4;
15 }
16
17 foo1 = "foo value";
18 let bar = "bar";
19
20 funcNameA(10);
21 }
22
23 funcName();
funcNameAExecutionContextObj = {
variableObject: {
argumentObject: {
0: arg1,
length: 1
},
arg1: 10,
foo1: undefined,
foo2: undefined
},
scopechain: [funcNameA execution context, funcName execution context,
Global execution context],
this:
}
> end of code. Hence...
> scopechain is set
> this is set
>
> As there is no other code, JS engine will start the execution phase
49. 1 console.log(c);
2 var b = 1;
var b;
console.log(c);
b=1;
> Uncaught ReferenceError: c is not defined
50. 1 function funcA(condition) {
2 console.log(var1);
3 if (condition) {
4 var var1 = "value of var1";
5 // do something
6 }
7 }
function funcA(condition) {
var var1;
console.log(var1);
if (condition) {
var1 = "value of var1";
// do something
}
}
> undefined
52. 1 var adder = (num) => {
2 var sum = 0;
3 return () => {
4 sum += num;
5 console.log(sum);
6 }
7 }
8
9 var adder2 = adder(2);
10 adder2(); //2
11 adder2(); //4
12 adder2(); //6
13 adder2(); //8
> a closure is a stack frame which is allocated when a function
starts its execution, and not freed after the function returns (as if
a 'stack frame' were allocated on the heap rather than the stack!).
> https://stackoverflow.com/questions/111102/how-do-javascript-closures-work
53. 1 var classA = function () {};
2
3 function func() {
4 var funcClassA = new classA();
5
6 function unreachable() {
7 funcClassA
8 };
9 return function () {};
10 }
11
12 var funVar = func();
>
54. 1 var classA = function () {};
2
3 function func() {
4 var funcClassA = new classA();
5
6 return function () {};
7 }
8
9 var funVar = func();
>