TechLead
Intermedio
15 min lectura

Preguntas de Entrevista JavaScript

Preguntas esenciales de JavaScript para entrevistas

Preguntas Esenciales de Entrevista JavaScript

Domina los conceptos fundamentales y avanzados de JavaScript necesarios para entrevistas técnicas.

1. Explica Hoisting en JavaScript

Hoisting es el comportamiento de JavaScript de mover declaraciones al inicio de su scope:

// Hoisting de variables
console.log(x); // undefined (no error)
var x = 5;

// Equivalente a:
var x;
console.log(x);
x = 5;

// let y const NO se elevan de la misma manera
console.log(y); // ReferenceError: Cannot access before initialization
let y = 10;

// Hoisting de funciones
sayHello(); // "Hola!" - funciona
function sayHello() {
  console.log("Hola!");
}

// Expresiones de función NO se elevan
greet(); // TypeError: greet is not a function
var greet = function() {
  console.log("Saludos!");
};

2. ¿Cuál es la Diferencia Entre var, let y const?

// var - function scope, hoisting
function example() {
  var x = 1;
  if (true) {
    var x = 2;  // Misma variable!
    console.log(x); // 2
  }
  console.log(x); // 2
}

// let - block scope, no hoisting
function example2() {
  let x = 1;
  if (true) {
    let x = 2;  // Variable diferente!
    console.log(x); // 2
  }
  console.log(x); // 1
}

// const - block scope, inmutable (referencia)
const obj = { name: "Juan" };
obj.name = "Pedro";  // OK - modificar propiedades
obj = {};            // Error - no se puede reasignar

const arr = [1, 2, 3];
arr.push(4);        // OK
arr = [];           // Error

3. Explica Closures

Un closure es una función que tiene acceso a variables de su scope externo:

// Closure básico
function createCounter() {
  let count = 0;
  
  return {
    increment() {
      count++;
      return count;
    },
    decrement() {
      count--;
      return count;
    },
    getCount() {
      return count;
    }
  };
}

const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.getCount());  // 2

// Closure en loop (problema común)
// ❌ Incorrecto
for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100);
}
// Output: 3, 3, 3

// ✅ Correcto
for (let i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100);
}
// Output: 0, 1, 2

4. ¿Qué es el Event Loop?

console.log('1');

setTimeout(() => {
  console.log('2');
}, 0);

Promise.resolve().then(() => {
  console.log('3');
});

console.log('4');

// Output: 1, 4, 3, 2
// Call Stack → Microtasks (Promises) → Macrotasks (setTimeout)

Orden de ejecución:

  1. Call Stack (código síncrono)
  2. Microtasks (Promises, queueMicrotask)
  3. Macrotasks (setTimeout, setInterval)

5. Explica Promesas y Async/Await

// Promesa básica
const fetchData = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const data = { user: "Juan" };
      resolve(data);
      // reject(new Error("Error"));
    }, 1000);
  });
};

// Usando .then()
fetchData()
  .then(data => console.log(data))
  .catch(error => console.error(error))
  .finally(() => console.log("Completado"));

// Usando async/await
async function getData() {
  try {
    const data = await fetchData();
    console.log(data);
  } catch (error) {
    console.error(error);
  } finally {
    console.log("Completado");
  }
}

// Promesas en paralelo
const urls = ['url1', 'url2', 'url3'];

// Esperar todas
const results = await Promise.all(
  urls.map(url => fetch(url))
);

// Primera en completar
const first = await Promise.race(
  urls.map(url => fetch(url))
);

// Todas completadas (fulfilled o rejected)
const all = await Promise.allSettled(
  urls.map(url => fetch(url))
);

6. ¿Qué es 'this' y Cómo Funciona?

// Contexto global
console.log(this); // window (browser) o global (Node.js)

// Método de objeto
const obj = {
  name: "Juan",
  greet() {
    console.log(`Hola, ${this.name}`);
  }
};
obj.greet(); // "Hola, Juan"

// Función regular vs Arrow Function
const person = {
  name: "Juan",
  regularFunction: function() {
    console.log(this.name); // "Juan"
  },
  arrowFunction: () => {
    console.log(this.name); // undefined (hereda this del scope externo)
  }
};

// call, apply, bind
function greet(greeting) {
  console.log(`${greeting}, ${this.name}`);
}

const user = { name: "Juan" };

greet.call(user, "Hola");     // "Hola, Juan"
greet.apply(user, ["Hola"]);  // "Hola, Juan"
const boundGreet = greet.bind(user);
boundGreet("Hola");            // "Hola, Juan"

7. Explica Prototype y Herencia

// Constructor function
function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.greet = function() {
  console.log(`Hola, soy ${this.name}`);
};

const john = new Person("John", 30);
john.greet(); // "Hola, soy John"

// ES6 Classes (sintaxis más limpia)
class Animal {
  constructor(name) {
    this.name = name;
  }
  
  speak() {
    console.log(`${this.name} hace un sonido`);
  }
}

class Dog extends Animal {
  constructor(name, breed) {
    super(name);
    this.breed = breed;
  }
  
  speak() {
    console.log(`${this.name} ladra`);
  }
}

const dog = new Dog("Rex", "Labrador");
dog.speak(); // "Rex ladra"

8. ¿Qué es Destructuring?

// Array destructuring
const arr = [1, 2, 3, 4, 5];
const [first, second, ...rest] = arr;
console.log(first, second, rest); // 1, 2, [3, 4, 5]

// Object destructuring
const user = {
  name: "Juan",
  age: 30,
  email: "juan@example.com"
};

const { name, age, email: correo } = user;
console.log(name, age, correo); // Juan, 30, juan@example.com

// Valores por defecto
const { name, country = "España" } = user;

// Nested destructuring
const data = {
  user: {
    profile: {
      name: "Juan"
    }
  }
};

const { user: { profile: { name: userName } } } = data;
console.log(userName); // "Juan"

// En parámetros de función
function greet({ name, age }) {
  console.log(`Hola ${name}, tienes ${age} años`);
}

greet({ name: "Juan", age: 30 });

9. Explica Map, Filter y Reduce

const numbers = [1, 2, 3, 4, 5];

// Map - transforma cada elemento
const doubled = numbers.map(n => n * 2);
console.log(doubled); // [2, 4, 6, 8, 10]

// Filter - filtra elementos
const evens = numbers.filter(n => n % 2 === 0);
console.log(evens); // [2, 4]

// Reduce - reduce a un valor único
const sum = numbers.reduce((acc, n) => acc + n, 0);
console.log(sum); // 15

// Ejemplo complejo: agrupar por propiedad
const users = [
  { name: "Juan", age: 25 },
  { name: "Ana", age: 30 },
  { name: "Pedro", age: 25 }
];

const groupedByAge = users.reduce((acc, user) => {
  const age = user.age;
  if (!acc[age]) acc[age] = [];
  acc[age].push(user);
  return acc;
}, {});

console.log(groupedByAge);
// { 25: [{name: "Juan", age: 25}, {name: "Pedro", age: 25}], 
//   30: [{name: "Ana", age: 30}] }

10. ¿Qué es el Spread Operator y Rest Parameters?

// Spread operator (...)
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2]; // [1, 2, 3, 4, 5, 6]

// Copiar arrays
const copy = [...arr1]; // [1, 2, 3]

// Spread en objetos
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3, d: 4 };
const merged = { ...obj1, ...obj2 }; // { a: 1, b: 2, c: 3, d: 4 }

// Sobrescribir propiedades
const user = { name: "Juan", age: 30 };
const updated = { ...user, age: 31 }; // { name: "Juan", age: 31 }

// Rest parameters
function sum(...numbers) {
  return numbers.reduce((acc, n) => acc + n, 0);
}

console.log(sum(1, 2, 3, 4, 5)); // 15

// Con destructuring
const [first, ...rest] = [1, 2, 3, 4, 5];
console.log(first, rest); // 1, [2, 3, 4, 5]

Mejores Prácticas de JavaScript

  • ✓ Usa const por defecto, let cuando sea necesario, evita var
  • ✓ Usa arrow functions para callbacks cortos
  • ✓ Prefiere async/await sobre promesas encadenadas
  • ✓ Usa destructuring para código más limpio
  • ✓ Aprovecha métodos de array como map, filter, reduce
  • ✓ Maneja errores apropiadamente con try/catch
  • ✓ Evita modificar el prototype de objetos nativos