Fly with code

Get wet inside ocean of code

0%

Go deep behind hoisting

Basic about hoisting

We all know that when you declare a variable in JS,but you don’t assign value to it

1
2
3
4
5
6
7
var a;
console.log(a); // undefined
```
Then, let's do a little adjustment.
```js
console.log(a); // undefined
var a;

The result is still the same !

Imagine it ! due to hoisting , var a; is raised to the top of all codes.
But, remember, the real position of code doesn’t move at all.
It all give credits to manipulation by JS engine.

But, be careful, only the declared variable will activate hoisting, value assignment doesn’t.
For example,

1
2
console.log(a); // undefined
var a = 'apple';

The real execution sequence is

1
2
3
var a;
console.log(a) // undefined
a = 'apple';

Does hoisting also happen inside function ?

Yes, it does.

1
2
3
4
5
function banana(){
console.log(apple);
var apple = 3
};
banana(); // undefined

What if we pass a value into the function ?

1
2
3
4
5
function banana(v){
console.log(v);
var apple = 3;
};
banana(99); // 99

The answer is 99, not undefined
But why ???

One more example,

1
2
3
var orange = 5;
var orange;
console.log(orange); // 5

Answer is 5, not undefined

Hoisting priority

1
2
3
console.log(a); // ƒ a(){}
var a;
function a(){};

Answer is ƒ a(){}, not undefined
The real execution sequence is,

1
2
3
function a(){};
var a;
console.log(a); // ƒ a(){}

Does let and const in ES6 also have Hoisting ?

Yes, it does, but a little bit different from var.
What does this mean ?

For example,

1
2
console.log(a) // ReferenceError: a is not defined
let a;

From this example, we will think, let doesn’t have hoisting.
If it has , the result should be undefined

Then, let’s check another example,

1
2
3
4
5
6
var a = 10;
function test(){
console.log(a);
let a;
};
test(); // Uncaught SyntaxError

Answer is Uncaught SyntaxError, not 10
Seems hoisting still happens !

How does hoisting work ?

According to ECMAScript

When control is transferred to ECMAScript executable code,
control is entering an execution context.
Active execution contexts logically form a stack.
The top execution context on this logical stack is the running execution context.
A new execution context is created whenever control is transferred
from the executable code associated with the currently running execution context
to executable code that is not associated with that execution context.

Means each time you create a function, an EC will also be created.
All data related with this function will be stored in this EC.

And according to another part from ECMAScript

Every execution context has associated with it a variable object.
Variables and functions declared in the source text are added as
properties of the variable object. For function code, parameters
are added as properties of the variable object.

Each EV has their own variable object (VO)
All declared variable and functions will be added into VO.

On entering an execution context, the properties are bound
to the variable object in the following order

When entering EC, data will be put into VO as below sequence.

For function code: for each formal parameter, as defined
in the FormalParameterList, create a property of the variable object
whose name is the Identifier and whose attributes are determined
by the type of code. The values of the parameters are supplied
by the caller as arguments to [[Call]].

If the caller supplies fewer parameter values than
there are formal parameters, the extra formal parameters have value undefined

Means if you pass a parameter into function, then this parameter will be put into VO first.
If this parameter has no value, then it will be set as undefined

Therefore, parameter has the top priority

For each FunctionDeclaration in the code, in source text order,
create a property of the variable object whose name is the Identifier
in the FunctionDeclaration, whose value is the result returned by
creating a Function object as described in 13, and whose attributes
are determined by the type of code.

If the variable object already has a property with this name,
replace its value and attributes. Semantically,
this step must follow the creation of FormalParameterList properties.

For function declaration, it will add a property in VO.
If have the property with the same name, then the value will be replaced.

For each VariableDeclaration or VariableDeclarationNoIn in the code,
create a property of the variable object whose name is the Identifier
in the VariableDeclaration or VariableDeclarationNoIn, whose value is
undefined and whose attributes are determined by the type of code.
If there is already a property of the variable object with the name
of a declared variable, the value of the property
and its attributes are not changed.

If the variable object already has a property with this name,
replace its value and attributes. Semantically,
this step must follow the creation of FormalParameterList properties.

For variable declaration, it will add a property in VO.
If have the property with the same name, then the value won’t be replaced.

So, while entering EC but function yet to be executed, it will follow

  • Add parameter into VC and set value, if no value, then set as undefined
  • Declare function and add it into VC, replace existed with the same name.
  • Declare variable and add it into VC, ignore existed property with the same name.

For example,

1
2
3
4
5
function test(v){
console.log(v);
var v = 3;
};
test(10); // 10

The real execution process is

  1. Enter VC and build VO.
  2. Add v(parameter) into VO, and set its value as 10.
  3. Declare variable v
  4. Property V already exists in VO, then ignore V.
1
2
3
4
5
6
function test(v){
var v; // ignore existed property with the same name
console.log(v); // v=10
v = 3; // v=3
};
test(10); // 10

Compiled vs Interpreted

We all know JS is an Interpreted language.
It will run the code line by line, from top to bottom.
But, is it a 100% Interpreted ? or just partly ?

If JS runs line by lien, then how could hoisting happen ?
It’s impossible.

Indeed, there is also complier in JS, means
some part of JS is Compiled language.
And it makes hoisting to come true in JS.

Temporal Dead Zone

About let and const, it also has hoisting behavior.

In terms of var
When hoisting happens, then its value will be initialized as undefined

In terms of let and const
When hoisting happens, then its value won’t be initialized.
But,if you tried to load value before value assignment, there will be an error.
This time period between hoisting and value assignment, called TDZ.

Means you can’t try to load the variable value before value assignment.

Additional Knowledge

Hoisting in JavaScript
我知道你懂 hoisting,可是你了解到多深?