Saltar al contenido principal

[Medium] 📄 Hoisting

1. What's Hoisting ?

La ejecución de JS se puede dividir en dos fases: la fase de creación y la fase de ejecución:

var name = 'Pitt';
console.log(name); // print Pitt

Debido a la característica de Hoisting, el código anterior debe entenderse como: primero se declara la variable y luego se ejecuta la asignación.

// create
var name;

// execute
name = 'Pitt';
console.log(name);

Las funciones son diferentes a las variables: se asignan a la memoria durante la fase de creación. La declaración de función es la siguiente:

getName();

function getName() {
console.log('string'); // print string
}

La razón por la que el código anterior puede ejecutarse normalmente e imprimir console.log sin generar un error es la siguiente lógica: la function se eleva primero a la parte superior, y luego se ejecuta la llamada a la function.

// create
function getName() {
console.log('string');
}

// execute
getName();

Sin embargo, hay que tener en cuenta que con esta característica de Hoisting, es necesario prestar atención al orden de escritura cuando se usan expresiones.

En la fase de creación, la function tiene la máxima prioridad, seguida por las variables.

Correct

name = 'Yumy';
console.log(name); // print Yumy
var name;

// --- Equal to ---

// create
var name;

// execute
name = 'Yumy';
console.log(name); // print Yumy

Wrong

console.log(name); // print undefined
var name = 'Jane';

// --- Equal to ---

// create
var name;

// execute
console.log(name); // print undefined,porque aún no se ha asignado un valor, solo se obtiene el undefined por defecto
name = 'Pitt';

2. What's name printed ?

whoseName();

function whoseName() {
if (name) {
name = 'Nini';
}
}

var name = 'Pitt';
console.log(name);

Answer

// create
function whoseName() {
if (name) {
name = 'Nini';
}
}
var name;

// execute
whoseName();
name = 'Pitt';
console.log(name); // print Pitt

name en whoseName() recibe undefined, por lo que no entra en la condición.

Sin embargo, como hay otra asignación debajo de la declaración de función, incluso si la condición en la function se cumpliera, finalmente se imprimiría Pitt.


3. Declaración de función vs Declaración de variable: Prioridad de Hoisting

Pregunta: Función y variable con el mismo nombre

Determine el resultado de salida del siguiente código:

console.log(foo);
var foo = '1';
function foo() {}

Respuesta incorrecta (malentendido común)

Muchas personas creen que:

  • Se imprime undefined (pensando que var se eleva primero)
  • Se imprime '1' (pensando que la asignación afecta)
  • Da error (pensando que el mismo nombre causa conflicto)

Salida real

[Function: foo]

¿Por qué?

Esta pregunta examina las reglas de prioridad del Hoisting:

Prioridad de Hoisting: Declaración de función > Declaración de variable

// Código original
console.log(foo);
var foo = '1';
function foo() {}

// Equivalente a (después del Hoisting)
// Fase 1: Fase de creación (Hoisting)
function foo() {} // 1. La declaración de función se eleva primero
var foo; // 2. La declaración de variable se eleva (pero no sobrescribe la función existente)

// Fase 2: Fase de ejecución
console.log(foo); // En este momento foo es una función, salida [Function: foo]
foo = '1'; // 3. Asignación de variable (sobrescribe la función)

Conceptos clave

1. Las declaraciones de función se elevan completamente

console.log(myFunc); // [Function: myFunc]

function myFunc() {
return 'Hello';
}

2. Las declaraciones de variable con var solo elevan la declaración, no la asignación

console.log(myVar); // undefined

var myVar = 'Hello';

3. Cuando la declaración de función y la declaración de variable tienen el mismo nombre

// Orden después del hoisting
function foo() {} // La función se eleva y se asigna primero
var foo; // La declaración de variable se eleva, pero no sobrescribe la función existente

// Por lo tanto foo es una función
console.log(foo); // [Function: foo]

Flujo de ejecución completo

// Código original
console.log(foo); // ?
var foo = '1';
function foo() {}
console.log(foo); // ?

// ======== Equivalente a ========

// Fase de creación (Hoisting)
function foo() {} // 1. Elevación de declaración de función (elevación completa, incluyendo el cuerpo)
var foo; // 2. Elevación de declaración de variable (pero no sobrescribe foo, porque ya es una función)

// Fase de ejecución
console.log(foo); // [Function: foo] - foo es una función
foo = '1'; // 3. Asignación de variable (ahora sí sobrescribe la función)
console.log(foo); // '1' - foo se convierte en string

Ejercicios avanzados

Ejercicio A: Influencia del orden

console.log(foo); // ?
function foo() {}
var foo = '1';
console.log(foo); // ?

Respuesta:

[Function: foo] // Primera salida
'1' // Segunda salida

Razón: El orden del código no afecta el resultado del Hoisting. La prioridad de elevación sigue siendo: función > variable.

Ejercicio B: Múltiples funciones con el mismo nombre

console.log(foo); // ?

function foo() {
return 1;
}

var foo = '1';

function foo() {
return 2;
}

console.log(foo); // ?

Respuesta:

[Function: foo] { return 2; } // Primera salida (la función posterior sobrescribe la anterior)
'1' // Segunda salida (la asignación de variable sobrescribe la función)

Razón:

// Después del hoisting
function foo() {
return 1;
} // Primera función

function foo() {
return 2;
} // La segunda función sobrescribe la primera

var foo; // Declaración de variable (no sobrescribe la función)

console.log(foo); // [Function: foo] { return 2; }
foo = '1'; // Asignación de variable (sobrescribe la función)
console.log(foo); // '1'

Ejercicio C: Expresión de función vs Declaración de función

console.log(foo); // ?
console.log(bar); // ?

var foo = function () {
return 1;
};

function bar() {
return 2;
}

Respuesta:

undefined; // foo es undefined
[Function: bar] // bar es una función

Razón:

// Después del hoisting
var foo; // Elevación de declaración de variable (la expresión de función solo eleva el nombre de variable)
function bar() {
return 2;
} // Elevación completa de declaración de función

console.log(foo); // undefined
console.log(bar); // [Function: bar]

foo = function () {
return 1;
}; // Asignación de expresión de función

Diferencia clave:

  • Declaración de función: function foo() {} → se eleva completamente (incluyendo el cuerpo de la función)
  • Expresión de función: var foo = function() {} → solo se eleva el nombre de la variable, el cuerpo de la función no se eleva

let/const no tienen este problema

// var tiene problemas de hoisting
console.log(foo); // undefined
var foo = '1';

// let/const tienen zona muerta temporal (TDZ)
console.log(bar); // ReferenceError: Cannot access 'bar' before initialization
let bar = '1';

// let/const con el mismo nombre que una función genera error
function baz() {} // SyntaxError: Identifier 'baz' has already been declared
let baz = '1';

Resumen de prioridad de Hoisting

Prioridad de Hoisting (de mayor a menor):

1. Declaración de función (Function Declaration)
├─ function foo() {} ✅ se eleva completamente
└─ prioridad más alta

2. Declaración de variable (Variable Declaration)
├─ var foo ⚠️ solo se eleva la declaración, no la asignación
└─ no sobrescribe funciones existentes

3. Asignación de variable (Variable Assignment)
├─ foo = '1' ✅ sobrescribe la función
└─ ocurre en la fase de ejecución

4. Expresión de función (Function Expression)
├─ var foo = function() {} ⚠️ se trata como asignación de variable
└─ solo se eleva el nombre de variable, no el cuerpo de la función

Puntos clave en entrevistas

Al responder este tipo de preguntas, se recomienda:

  1. Explicar el mecanismo de Hoisting: Se divide en fase de creación y fase de ejecución
  2. Enfatizar la prioridad: Declaración de función > Declaración de variable
  3. Dibujar el código después del Hoisting: Mostrar al entrevistador tu comprensión
  4. Mencionar las mejores prácticas: Usar let/const para evitar problemas de Hoisting con var

Ejemplo de respuesta en entrevista:

"Esta pregunta examina la prioridad del Hoisting. En JavaScript, la declaración de función tiene mayor prioridad de elevación que la declaración de variable.

El proceso de ejecución se divide en dos fases:

  1. Fase de creación: function foo() {} se eleva completamente a la parte superior, luego la declaración var foo se eleva pero no sobrescribe la función existente.
  2. Fase de ejecución: En console.log(foo), foo es una función en ese momento, por lo que se imprime [Function: foo]. Después, foo = '1' sobrescribe foo con un string.

La mejor práctica es usar let/const en lugar de var, y colocar las declaraciones de función en la parte superior para evitar este tipo de confusiones."


Temas relacionados