What will happen if you execute code bellow?
giveCookie();
function giveCookie() {
console.log('๐ช');
}
console.log(candy);
var candy = '๐ฌ';
console.log(broccoli);
let broccoli = '๐ฅฆ';
Correct answers are
giveCookie();
function giveCookie() {
console.log('๐ช');
}
// Output: ๐ช
console.log(candy);
var candy = '๐ฌ';
// Output: undefined
console.log(broccoli);
let broccoli = '๐ฅฆ';
// Output: ReferenceError
The reason behind such results is fairly simple Javascript doesn't like vegies ๐.
Seriously though, it's called hoisting. Hoising is a word that is used to describe the perceived behavior of Javascript when it supposedly moves all declarations to the beginning of the scope. Basically according to this idea code above can be rewritten like so
function giveCookie() {
console.log('๐ช');
}
giveCookie();
// Output: ๐ช
var candy;
console.log(candy);
candy = '๐ฌ';
// Output: undefined
let broccoli;
console.log(broccoli);
broccoli = '๐ฅฆ';
// Output: undefined
noticed the difference? In an example with let
in the first case, it resulted in ReferenceError
however after rewriting it in the way how hoisting describes it, it resulted in undefined
. Basically hoisting is a lie, Javascript isn't moving declaration to the top. However, it may look like that because the execution of Javascript has two stages. In the first stage, the compiler goes over the code and handles declarations and scopes
giveCookie();
function giveCookie() { // Declare function giveCookie
// Create new scope
console.log('๐ช');
}
console.log(candy);
var candy = '๐ฌ'; // Declare variable candy, by default var is undefined
console.log(broccoli);
let broccoli = '๐ฅฆ'; // Declare variable broccoli, by default let & const are not assigned to anything
On the second stage code gets interpreted line-by-line
giveCookie();// Is there declared function giveCookie? YES -> console.log('๐ช');
function giveCookie() {
console.log('๐ช');
}
console.log(candy); // Is there declared variable candy? YES -> undefined
var candy = '๐ฌ';
console.log(broccoli); // Is there declared variable broccoli? YES -> nothing is assigned to it so ReferenceError!
let broccoli = '๐ฅฆ';
This RefferenceError of let
and const
is known as TDZ (Temporal Dead Zone). TDZ happens when you are trying to access a variable that isn't fully initialized. When the variable is declared but doesn't have any value assigned to it, because the line that assigns a variable to it wasn't yet been executed. This issue occurs only with let
and const
because var
by default, at the compilation stage, gets assigned undefined
, however, let
and const
get variables only at the interpretation stage.
More examples!
console.log(carrot);
let carrot = '๐ฅ';
// ReferenceError
function giveIceCream() {
console.log(iceCream);
}
let iceCream = '๐จ';
giveIceCream();
// ๐จ
In the first case, TDZ happens because Javascript still doesn't like vegies ๐, or because you are trying to access a variable before it was fully initialized. In the second case, you fully initialize a variable before executing a function that uses it so you get an ๐จ.
A bit more tricky example with scope
function sayHi() {
var name = 'Mark'; // Decleare and assign 'Mark' to name
if (name) { // name is truth, continue
let name = `Hi, ${name}` ; // ReferenceError
console.log(name);
}
}
sayHi();
This example can be brought down to let name = `Hi, ${name};
in which you are declaring let
inside of if statements scope, var name
is parent scope so it gets shadowed, and then you are trying to access it immediately before finalizing its declaration.