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

Made with Slides.com