JavaScript Hoisting

Teniendo en cuenta el siguiente código:

var message = 'Hello World';
console.log(message); // Hello World

Vale, creo que todos estamos de acuerdo con el resultado. Vamos a añadir una función autoejecutable:

var message = 'Hello World';

(function() {
  console.log(message); // Hello World
})();

Bastante lógico, creo que seguimos de acuerdo. Vamos a crear pues una variable local dentro de la función anónima:

var message = 'Hello World';

(function() {
  console.log(message); // undefined
  var message = 'Local World';
})();

WAT! ¿Por qué la variable message no está definida? ¿La variable declarada no debería tener efecto?

Hoisting de Variables

Dentro del scope de la función, el intérprete interno pasa a ubicar las variables al inicio del scope independientemente de donde se declaren. Sin embargo, sólo la declaration es "Hosteada". Si la variable está initialized, su valor, al inicio del scope, pasará a undefined.

Es importante diferenciar entre declaration y initialization.

Declaration

var message; //  the declaration

Initialization

message = 'Hello World'; // the initialization

Así pues el siguiente código sería una mala práctica:

var message = 'Hello World';

(function() {
  var one = 'Message 1';
  // Your code...
  var two = 'Message 2';
  // More code...
  var three = 'Message 3';
  // And more...
})();

¡Declara las variables al principio!

var message = 'Hello World';

(function() {
  var one, two, three; // variables declared
  one = 'Message 1'; // initialized
  // Your code...
  two = 'Message 2'; // initialized
  // More code...
  three = 'Message 3'; // initialized
  // And more...
})();

Así que volviendo al código original:

var message = 'Hello World';

(function() {
  console.log(message); // undefined
  var message = 'Local World';
})();

Entendemos que en el momento de la declaración la variable pasa a ubicarse al inicio (hoisted) del contexto pero como la inicialización no es "Hosteada" su valor pasa a ser undefined.