Hoisting
In JavaScript, functions and variables are hoisted.
Hoisting is JavaScript's behavior of moving declarations to the top of a scope (the global scope or the current function scope).
Hoisting
Declarations
Hoisting - Declarations
The variable or funtion is registered using a given name within the corresponding scope
Hoisting - Declarations
Function declaration
Variable declaration
function foo() {
};
Variables declared with var are available in the scope of the enclosing function. If there is no enclosing function, they are available globally.
Function declarations in JavaScript are hoisting the function definition. You can use the function before you declared it
var foo;
Hoisting - Declarations - Variables
Variables
var x; // Declaration and initialization
x = "Hello World"; // Assignment
// Or all in one
var y = "Hello World";
function sayHello(){
var hello = "Hello World";
return hello;
}
console.log(hello); //ReferenceError: hello is not defined
function sayHello(){
hello = "Hello World";
return hello;
}
console.log(hello); //logs "Hello World"
Hoisting - Declarations - Variables
(function() {
var foo = 1;
var bar = 2;
var baz = 3;
alert(foo + " " + bar + " " + baz);
})();
(function() {
var foo = 1;
alert(foo + " " + bar + " " + baz);
var bar = 2;
var baz = 3;
})();
(function() {
var foo = 1;
alert(foo + " " + bar + " " + baz);
var bar = 2;
})();
Hoisting - Declarations - Variables
(function() {
var foo = 1;
var bar = 2;
var baz = 3;
alert(foo + " " + bar + " " + baz);
// logs "1 2 3"
})();
(function() {
var foo = 1;
alert(foo + " " + bar + " " + baz);
// logs "1 undefined undefined"
var bar = 2;
var baz = 3;
})();
(function() {
var foo = 1;
alert(foo + " " + bar + " " + baz);
// Uncaught ReferenceError: baz is not defined
var bar = 2;
})();
Hoisting - Declarations - Variables
var txt = ["a","b","c"];
for (var i = 0; i < 3; ++i ) {
var msg = txt[i];
setTimeout(function() { alert(msg); }, i*1000);
}
Hoisting - Declarations - Variables
var txt = ["a","b","c"];
for (var i = 0; i < 3; ++i ) {
var msg = txt[i];
setTimeout(function() { alert(msg); }, i*1000);
}
// Alerts 'c', 'c', 'c'
var txt = ["a","b","c"];
for (var i = 0; i < 3; ++i ) {
setTimeout((function(msg) {
return function() { alert(msg); }
})(txt[i]), i*1000);
}
// Alerts 'a','b','c'
This example demonstrates that 'msg' is shared between the three invocations of 'alert'. Avoid this fate by getting in the habit of explicitly declaring the variables that your closure is closing over by passing them in as arguments and binding them at the time the closure is created, as below.
ES2015 let / const
Hoisting - Declarations - Variables - ES2015
ES2015 let / const
In ECMAScript 2015, let (const) will hoist the variable to the top of the block. However, referencing the variable in the block before the variable initiation results in a ReferenceError. The variable is in a "temporal dead zone" from the start of the block until the declaration is processed.
Let
let x; // Declaration
x = "Hello World"; // Initialization and Assignment
// Or all in one
let y = "Hello World";
const x = "Hello World";
Technically a constant isn’t a variable. The particularity of a constant is that you need to assign a value when declaring it and there is no way to reassign it. A const is limited to the scope of the enclosing block, like let.
let is the descendant of var in modern JavaScript. Its scope is not only limited to the enclosing function, but also to its enclosing block statement. A block statement is everything inside { and }, (e.g. an if condition or loop).
Hoisting - Declarations - Variables - ES2015
Const
Let
x = y = "global";
(function() {
x;
console.log(x);
y;
console.log(y);
var x = "local";
let y = "local";
}());
var a = 1;
var b = 2;
if (a === 1) {
var a = 11;
let b = 22;
console.log(a);
console.log(b);
}
console.log(a);
console.log(b);
Hoisting - Declarations - Variables - ES2015
Let
x = y = "global";
(function() {
x;
console.log(x); // undefined
y;
console.log(y); // ReferenceError y is not defined
var x = "local";
let y = "local";
}());
var a = 1;
var b = 2;
if (a === 1) {
var a = 11; // the scope is global
let b = 22; // the scope is inside the if-block
console.log(a); // 11
console.log(b); // 22
}
console.log(a); // 11
console.log(b); // 2
Hoisting - Declarations - Variables - ES2015
Hoisting - Declarations - Functions
Function declaration
function foo() {
};
Anonymous function
function() {
};
Function Expression
var functionExpression = function() {
};
Hoisting - Declarations - Functions
Function declaration
hoisted(); // logs "foo"
function hoisted() {
console.log("foo");
}
Function Expression
notHoisted(); // TypeError: notHoisted is not a function
var notHoisted = function() {
console.log("bar");
};
Hoisting - Declarations - Functions
showState();
function showState() {
console.log("Ready");
}
var showState = function() {
console.log("Idle");
};
Hoisting - Declarations - Functions
showState(); // output: Ready
function showState() {
console.log("Ready");
}
var showState = function() {
console.log("Idle");
};
function showState() { // moved to the top (function declaration)
console.log("Ready");
}
var showState; // moved to the top (variable declaration)
showState();
showState = function() { // left in place (variable assignment)
console.log("Idle");
};
Hoisting - Declarations - Functions
var showState = function() {
console.log("Idle");
};
function showState() {
console.log("Ready");
}
showState();
Hoisting - Declarations - Functions
var showState = function() {
console.log("Idle");
};
function showState() {
console.log("Ready");
}
showState(); // output: Idle
function showState(){ // moved to the top (function declaration)
console.log("Ready");
}
var showState; // moved to the top (variable declaration)
showState = function(){ // left in place (variable assignment)
console.log("Idle");
};
showState();
Hoisting - Declarations - Functions
function getMysteryNumber () {
function chooseMystery() {
return 12;
}
return chooseMystery();
function chooseMystery() {
return 7;
}
}
Hoisting - Declarations - Functions
function getMysteryNumber () {
function chooseMystery() {
return 12;
}
return chooseMystery();
function chooseMystery() {
return 7;
}
}
function getMysteryNumber () {
function chooseMystery() {
return 12;
}
function chooseMystery() {
return 7;
}
return chooseMystery();
}
chooseMystery(); // returns 7
All declarations, both functions and variables, are hoisted to the top of the containing scope, before any part of your code is executed.
Functions are hoisted first, and then variables.
Function declarations have priority over variable declarations, but not over variable assignments.
Hoisting - Summary
Because of hoisting, all var/let/const statements in a function or block scope should be placed as near to the top of the function or block scope as possible. This best practice increases the clarity of the code.
Hoisting - Best practice
Hoisting - Best practice - Example - Module pattern
var Module = (function () {
var privateMethod = function () {
// private
};
var someMethod = function () {
// public
};
var anotherMethod = function () {
// public
};
return {
someMethod: someMethod,
anotherMethod: anotherMethod
};
})();
Module.someMethod();
Hoisting - Conclusion
Hoisting
By tietyk
Hoisting
Its involvement with scope, closures, execution order, let/const, how you setup your functions and why the module pattern works.
- 1,879