Back to Developer
JavaScript
JavaScript esencial para testers y desarrolladores — fundamentos del lenguaje, asincronía y POO.
Fundamentos
const vs let vs var: ¿cuál usar y por qué?
Usa
const por defecto (la asignación no se puede reasignar), let cuando necesites reasignar, y evita var — tiene ámbito de función y hoisting con comportamiento confuso, mientras const/let tienen ámbito de bloque. Ojo: const impide la reasignación, no la mutación: las propiedades de un objeto const sí pueden cambiar.¿Qué hacen map, filter y reduce, y en qué se diferencian de forEach?
map transforma cada elemento y devuelve un nuevo array del mismo tamaño; filter devuelve un nuevo array solo con los elementos que pasan un predicado; reduce acumula el array en un único valor. forEach solo itera por efectos secundarios y no devuelve nada. map/filter/reduce son puros (no mutan el original); push/pop/splice/sort sí mutan.¿Para qué sirven el destructuring y el operador spread?
El destructuring desempaqueta valores de arrays u objetos en variables:
const { name, age } = user, o en parámetros de función function f({ id }). El spread (...) copia/fusiona: const merged = { ...base, env: 'prod' } o const all = [...a, ...b]. Las copias con spread son superficiales — los objetos anidados se comparten, no se clonan.¿Qué hacen el optional chaining (?.) y el nullish coalescing (??)?
El optional chaining devuelve
undefined en lugar de lanzar error cuando un valor intermedio es null/undefined: res.data?.user?.name. El nullish coalescing devuelve el lado derecho solo cuando el izquierdo es null o undefined (no para 0 o '', a diferencia de ||): const total = res.data?.order?.total ?? 0. Ambos son habituales al aseverar sobre la forma de respuestas de API.Asincronía y POO
¿Qué es una Promise y qué estados puede tener?
Una
Promise representa el resultado futuro de una operación asíncrona. Está pending mientras está en curso, fulfilled en éxito (se maneja con .then) o rejected en fallo (se maneja con .catch); .finally siempre se ejecuta. Promise.all corre muchas en paralelo y rechaza si alguna falla, Promise.allSettled espera a todas pase lo que pase, y Promise.race resuelve con la primera que termina.¿Cómo se relaciona async/await con las Promises, y secuencial vs paralelo?
async/await es azúcar sintáctico sobre las Promises: una función async siempre devuelve una Promise, y await pausa dentro de ella hasta que la Promise termina, manejando errores con try/catch. Esperar en secuencia (await a; await b) es lento; para trabajo independiente ejecútalo en paralelo con await Promise.all([a, b]).¿Qué hay que saber sobre las clases en JavaScript?
Una clase tiene un
constructor que fija campos de instancia con this, métodos de instancia, y miembros estáticos a los que se accede en la propia clase (MathUtils.PI), no en las instancias. Los getters/setters exponen propiedades calculadas o protegidas (get fahrenheit(), set celsius(v) con validación). Los métodos factory estáticos como ApiResponse.ok(body) son una forma limpia de crear instancias comunes.¿Cómo funcionan la herencia y el polimorfismo en JavaScript?
Una subclase usa
extends y debe llamar a super(...) en su constructor antes de usar this; puede sobrescribir métodos y llamar a super.metodo() para extender el comportamiento. El polimorfismo significa que la misma llamada se comporta distinto según la clase — p. ej. una lista de Vehiculo/Coche/Moto que implementan info(). instanceof comprueba la cadena de prototipos.¿Cómo se encapsula el estado en JavaScript?
Usa campos privados de clase con prefijo
# (this.#saldo) para que no se puedan leer ni escribir desde fuera; expón acceso controlado mediante getters y métodos que validen la entrada. El enfoque clásico anterior a # es un closure (una función factory con una variable privada). Devolver una copia (p. ej. [...this.#historial]) evita filtrar referencias internas.¿Qué patrones de diseño aparecen a menudo en frameworks de test?
Singleton (una instancia compartida, p. ej. un
Config), Factory (construir objetos configurados, p. ej. un HttpClient por entorno), Builder (construcción fluida paso a paso, p. ej. un RequestBuilder) y Observer/EventEmitter (suscribirse a eventos, como un test runner que emite pass/fail). La inyección de dependencias — pasar los colaboradores en vez de fijarlos en el código — hace que todos sean fáciles de mockear.