Dev.to WebDev 🛠 Dev 👁 0 📖 4 min read

Prepárate para tu entrevista frontend: 10 ejercicios de hoisting y scope (con respuestas)

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, an

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";

Solución
Un solo error: ReferenceError: Cannot access 'primera' before initialization.

La segunda línea nunca se ejecuta, porque el primer error detiene la ejecución.

Y lo más importante: 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;
};

Solución
5 y luego ReferenceError: Cannot access 'suma2' before initialization.

Las declaraciones de función hacen hoisting con todo y su cuerpo, así que se pueden llamar antes. 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");
};

Solución
TypeError: despedir is not a function.

Esta vez no es un 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();

Solución
undefined.

¡No 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;
}

Solución
ReferenceError: Cannot access 'x' before initialization.

Podrías esperar 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.

Esta es la mejor prueba de que let sí hace hoisting.


Ejercicio 8: sin declaración adentro

var a = 1;

function externa() {
  console.log(a);
  a = 2;
}

externa();
console.log(a);

Solución
1 y luego 2.

Dentro de 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);

Solución
"function" y luego "number".

Las dos declaraciones se registran, y en el hoisting gana la declaración de función. Después corre la línea 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";

Solución
"undefined" y luego ReferenceError: Cannot access 'enTDZ' before initialization.

Normalmente 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.
  1. Las clases hacen hoisting como let: están en la temporal dead zone hasta su declaración.
  2. Los parámetros por defecto se evalúan de izquierda a derecha. Cuando 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 👇

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.