(#4) ES Series Block Scoping

Hoisting: the mother of all problems for a beginner.

Accepting the concept of hoisting has always been difficult to a javascript beginner.

And if you are starting your career in javascript that too with es6 then you must know how es6 has resolved this problem with block scoping similar to c-type languages.

Hoisting could be explained with following example

1
2
Note: go through all the codes  snippets  and for best
learning experience, execute each snippets in your browser's console.

1: Getting started

1
console.log(test) // Uncaught ReferenceError: test is not defined

Reason: test is a variable which has never been declared or initialized.

2: Hoisting of a variable in ES5

1
2
3
4
5
6
7
8
9
function getValue(condition){
if(condition){
var value = 'blue';
return value;
} else {
console.log(value) // value exists here as undefined
}
console.log('value') // value exists here too as undefined.
}

Reason:

variable value gets hoisted, meaning it gets declared before the function is declared thus it is accessible through out function that’s why we get ‘undefined’. but its initialization only happens when the condition is meet.

Problem : unwanted variable available outside its scope.

This got resolved in es6 with the introduction of block scoped variables by using let and const.

3 : No hoisting in ES6

1
2
3
4
5
6
7
8
9
10
function getValue(condition){
if(condition){
let value = 'blue';
return value;
}else{
// value does not exists here
return null
}
// value does not exits here
}

Reason : let makes sure that value variable is available to its defined scope which is inside if condition.

4 : No redeclaration of variable in ES6

1
2
var value = 'blue';
let value = 'red'; //Uncaught TypeError: Identifier 'value' has already been declared

But if you are in different scope then they won’t throw the error.

5: Every const must be initialized on declaration

1
2
const NAME = 'aswin';
const VIVA; // Syntax error: must be initialized.

6 : Const declaration prevents the binding and not the value itself.

1
2
3
4
5
6
7
8
9
10
const TEST = 1;
const TEST = 2; // throw error
const VIVA = {
name: 'aswin'
};
const VIVA.name = 'devarajan' // works perfectly
VIVA = {
name: 'devarajan' // will throw error.
}

7: Using variable in loop

1
2
3
4
5
6
7
8
9
10
// using variable in loop with var
for(var i = 0; i<10; i++){
console.log(i)
}
console.log('after loop', i) // i is still accessable as 10
// using variable in loop with let
for(let j = 0; j<10; j++){
console.log(j)
}
console.log('after loop', j) // throw error as j is not defined

Reason : since j is scope binding due to let it is not available outside the loop. But in case of i it is available due to hoisting.

8 : Using function in a loop

1
2
3
4
5
6
7
8
9
10

// using variable in loop
var funcs = []
for(let j = 0; j<10; j++){
funcs.push(function(){ return console.log(j);})
}
funcs.forEach(d){
d();
}

This would print 10 ten times. since the loop has been executed.

To resolve this we could use a Immediate Invoking Function (IIFS).

1
2
3
4
5
6
7
8
9
10
11
var funcs = [];
for (var i = 0; i < 10; i++) {
funcs.push((function(value) {
return function() {
console.log(value);
}
})(i))
}
funcs.forEach(function(func) {
func();
})

But with es6 you wont have to go through this pain since let would allow you to store each unique instance of variable.

1
2
3
4
5
6
7
8
9
  let funcs = [];
for(let j=0; j<10; j++){
funcs.push(function(){
return console.log(j);
})
}
funcs.forEach(function(func){
func();
})

This is the end of the block scope related functionality added in ES6. I would be adding more examples as I come across.