[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:
- Explicar el mecanismo de Hoisting: Se divide en fase de creación y fase de ejecución
- Enfatizar la prioridad: Declaración de función > Declaración de variable
- Dibujar el código después del Hoisting: Mostrar al entrevistador tu comprensión
- 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:
- Fase de creación:
function foo() {}se eleva completamente a la parte superior, luego la declaraciónvar foose eleva pero no sobrescribe la función existente.- 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/consten lugar devar, y colocar las declaraciones de función en la parte superior para evitar este tipo de confusiones."