En el post de variables, tipos de dato, scope y hoisting vimos los conceptos. Ahora vamos a practicar como de verdad lo evalúan en las entrevistas: "¿Qué imprime este código?"
Cómo usar este post: lee cada ejercicio, anota tu respuesta y después abre la solución. Si quieres comprobarlo, córrelos en la consola de tu navegador. Todas las respuestas están probadas en Node.js.
Repaso rápido
| Declaración | ¿Hace hoisting? | Antes de su línea |
|---|---|---|
var |
Sí | undefined |
let / const
|
Sí, pero sin inicializar |
ReferenceError (temporal dead zone) |
Declaración de function
|
Sí, completa | Se puede llamar |
| Expresión de función / arrow | Solo la variable | Depende de si es var, let o const
|
class |
Sí, pero sin inicializar | ReferenceError |
Y recuerda: el código no se mueve. Antes de ejecutar un scope, el motor registra sus declaraciones. Lo que cambia es si se inicializan o no.
Ejercicio 1: para calentar
console.log(saludo);
var saludo = "Hola";
console.log(saludo);
Solución
undefined y luego "Hola".
saludo se registra antes de que corra el código y se inicializa como undefined. La asignación = "Hola" pasa en la línea 2, así que el primer log ve undefined.
Ejercicio 2: let y const
console.log(primera);
console.log(segunda);
let primera = "Soy un let";
const segunda = "Soy un const";
La segunda línea nunca se ejecuta, porque el primer error detiene la ejecución. Y lo más importante: Solución
Un solo error: ReferenceError: Cannot access 'primera' before initialization.
primera y segunda sí hacen hoisting. Si no lo hicieran, el error sería "primera is not defined". "Cannot access before initialization" significa que el motor sabe que la variable existe, pero todavía está en la temporal dead zone.
Ejercicio 3: tres tipos de funciones
console.log(suma(2, 3));
function suma(a, b) {
return a + b;
}
console.log(suma2(2, 3));
const suma2 = function (a, b) {
return a + b;
};
Las declaraciones de función hacen hoisting con todo y su cuerpo, así que se pueden llamar antes. Solución
5 y luego ReferenceError: Cannot access 'suma2' before initialization.
suma2 es solo una variable const que guarda una función, así que sigue las reglas de const. Lo mismo pasa con las arrow functions.
Ejercicio 4: la misma función, pero con var
despedir();
var despedir = function () {
console.log("Adiós");
};
Esta vez no es un Solución
TypeError: despedir is not a function.
ReferenceError. Con var, despedir existe y vale undefined, y llamar a undefined() es un TypeError. A los entrevistadores les encanta esta diferencia.
Ejercicio 5: el bloque que se escapa
if (true) {
var escapa = "var";
let seQueda = "let";
}
console.log(escapa);
console.log(seQueda);
Solución
"var" y luego ReferenceError: seQueda is not defined.
var ignora el scope de bloque; pertenece a la función que lo contiene (o al scope global). let solo existe dentro de las { }.
Ejercicio 6: shadowing con var
var x = 1;
function prueba() {
console.log(x);
var x = 2;
}
prueba();
¡No Solución
undefined.
1! Dentro de prueba hay un var x local, que se registra al inicio de la función y se inicializa como undefined. Esa variable tapa (shadowing) a la x global, así que el log ve la local antes de su asignación.
Ejercicio 7: shadowing con let
let x = 1;
{
console.log(x);
let x = 2;
}
Podrías esperar Esta es la mejor prueba de que Solución
ReferenceError: Cannot access 'x' before initialization.
1, del scope de afuera. Pero el bloque interno tiene su propio let x, que hace hoisting al inicio del bloque y queda atorado en la temporal dead zone. La x interna tapa a la externa desde la primera línea del bloque.let sí hace hoisting.
Ejercicio 8: sin declaración adentro
var a = 1;
function externa() {
console.log(a);
a = 2;
}
externa();
console.log(a);
Dentro de Solución
1 y luego 2.
externa no hay var, let ni const, así que a se refiere a la variable de afuera por la scope chain. La función la lee y luego la reasigna.
Ejercicio 9: el mismo nombre, dos declaraciones
console.log(typeof foo);
var foo = 1;
function foo() {}
console.log(typeof foo);
Las dos declaraciones se registran, y en el hoisting gana la declaración de función. Después corre la línea Solución
"function" y luego "number".
foo = 1 y la reemplaza por un número. (Por favor, nunca escribas esto en código real.)
Ejercicio 10: typeof y la TDZ
console.log(typeof noDeclarada);
console.log(typeof enTDZ);
let enTDZ = "hola";
Normalmente Solución
"undefined" y luego ReferenceError: Cannot access 'enTDZ' before initialization.
typeof es "seguro": con una variable que no existe para nada, regresa "undefined" en lugar de lanzar un error. Pero una variable en la temporal dead zone es diferente. Sí existe, solo que no está inicializada, y typeof no te salva.
Ronda extra
Dos rápidos que salen en entrevistas más avanzadas:
new Usuario();
class Usuario {}
function saludar(a = b, b = "hola") {
return a;
}
saludar();
Soluciones
Los dos lanzan un ReferenceError.
let: están en la temporal dead zone hasta su declaración.a intenta leer b, b todavía no se ha inicializado.
¿Cómo te fue?
- De 10 a 12: estás lista o listo para esta parte de la entrevista.
- De 6 a 9: repasa la temporal dead zone y el shadowing (ejercicios 6, 7 y 10).
- Menos de 6: regresa al post de conceptos y vuelve a intentarlo en un par de días.
¿Cuál te hizo caer? Cuéntame en los comentarios 👇
Top comments (0)