¿Qué es ES6+?
En junio de 2015, JavaScript recibió su actualización más importante hasta la fecha. ECMAScript 2015, mejor conocido como ES6, añadió el alcance de bloque (block scoping), arrow functions, clases, módulos, promises y mucho más. El comité que mantiene el lenguaje se comprometió entonces a lanzar una nueva edición cada año, y “ES6+” se ha convertido en la abreviatura para referirse a toda esa era moderna.
No es necesario aprender cada una de las funcionalidades. Un pequeño grupo de ellas representa la gran mayoría del código cotidiano, y eso es precisamente lo que cubre esta guía. El hilo conductor de todas ellas es simple: expresar lo que quieres decir con menos ceremonia.
let y const
La característica más antigua es también la más importante. var tiene un alcance de función (function-scoped) y se comporta con el hoisting de maneras que suelen sorprender. let y const tienen un alcance de bloque (block-scoped), por lo que solo existen dentro del { } más cercano.
// scope.js
if (true) {
let message = "inside";
const limit = 10;
}
// message and limit are not defined out here
const evita la reasignación de la variable, lo que hace que tu intención sea obvia: este nombre no apuntará a otro lugar. No congela el valor, por lo que un array const aún puede ser mutado. Usa const por defecto, let cuando la reasignación sea realmente necesaria, y trata a var como algo del pasado.
Arrow functions
Las arrow functions son una sintaxis más corta con una diferencia de comportamiento importante: no tienen su propio this. Heredan el this del scope circundante, que es casi siempre lo que se busca en los callbacks.
// arrows.js
const add = (a, b) => a + b;
const square = (n) => {
return n * n;
};
const names = ["Ada", "Grace", "Linus"];
const upper = names.map((name) => name.toUpperCase());
Cuando el cuerpo es una única expresión, se pueden omitir las llaves y el return. Los paréntesis alrededor de un único parámetro son opcionales. Debido a que las arrow functions capturan el this, son ideales para manejadores de eventos y métodos de arrays, pero no son adecuadas para métodos de objetos que necesiten su propio this.
Template literals
Las comillas invertidas (backticks) permiten crear strings que abarcan varias líneas e interpolar expresiones mediante ${ }.
// message.js
const name = "Ada";
const role = "engineer";
const greeting = `Hello, ${name}!
You are logged in as a ${role}.`;
Los template literals también admiten tagged templates, donde una función recibe las partes literales y los valores interpolados por separado. Este mecanismo es la base de muchas librerías de plantillas y estilos.
Destructuring
El destructuring permite extraer valores de arrays y objetos hacia variables, lo que elimina gran parte del acceso repetitivo a las propiedades.
// destructure.js
const user = { name: "Ada", age: 36, city: "London" };
const { name, age, city = "Unknown" } = user;
const coords = [51.5, -0.12];
const [lat, lng] = coords;
function greet({ name }) {
return `Hello, ${name}`;
}
Puedes renombrar variables durante el destructuring (const { name: userName } = user), definir valores por defecto y realizar el destructuring directamente en la lista de parámetros de una función; un patrón que se utiliza constantemente con las props de React y los objetos de configuración.
Spread y rest
Los mismos tres puntos cumplen dos funciones complementarias dependiendo de dónde aparezcan.
// spread.js
const a = [1, 2, 3];
const b = [4, 5];
const combined = [...a, ...b]; // spread: expand
const copy = { ...user, age: 37 }; // shallow clone + override
function sum(...numbers) { // rest: collect
return numbers.reduce((t, n) => t + n, 0);
}
Spread copia elementos en un nuevo array u objeto, lo cual es la base de las actualizaciones inmutables. Rest agrupa los argumentos o elementos restantes en un único array. Juntos, hacen que trabajar con colecciones sea mucho más agradable.
Parámetros por defecto y sintaxis abreviada
Las funciones pueden declarar valores por defecto y los literales de objeto pueden utilizar la sintaxis abreviada cuando el nombre de la propiedad coincide con el de una variable.
// config.js
function connect({ host = "localhost", port = 8080 } = {}) {
return `${host}:${port}`;
}
const name = "Ada";
const user = { name, greet() { return `Hi, ${this.name}`; } };
Los valores por defecto se evalúan únicamente cuando el argumento es undefined, que es generalmente el comportamiento deseado. Las propiedades y métodos abreviados reducen el ruido en el código con un uso intensivo de objetos.
Optional chaining y nullish coalescing
Estos dos operadores, añadidos en 2020, eliminaron montañas de comprobaciones defensivas.
// safe.js
const city = user?.address?.city;
const name = input ?? "anonymous";
user?.profile?.onLogin?.();
?. hace un cortocircuito hacia undefined si el valor a su izquierda es null o undefined. ?? proporciona un valor de respaldo solo cuando el lado izquierdo es null o undefined; a diferencia de ||, no trata a 0, "" o false como valores ausentes.
Métodos de Array
El prototipo de array está repleto de métodos que describen la intención en lugar de la mecánica de los bucles.
// arrays.js
const products = [
{ name: "Keyboard", price: 80, inStock: true },
{ name: "Mouse", price: 40, inStock: false },
{ name: "Cable", price: 10, inStock: true },
];
const names = products.map((p) => p.name);
const cheap = products.filter((p) => p.price < 50);
const total = products.reduce((sum, p) => sum + p.price, 0);
const available = products.some((p) => p.inStock);
const allCheap = products.every((p) => p.price < 100);
const mouse = products.find((p) => p.name === "Mouse");
map transforma, filter selecciona, reduce reduce una lista a un solo valor, find devuelve la primera coincidencia, y some/every comprueban una condición. Se pueden encadenar, no mutan el array original y se leen como una descripción de lo que quieres lograr.
Módulos
Los ES modules te permiten dividir el código en varios archivos y compartir únicamente lo que decidas.
// math.js
export function add(a, b) {
return a + b;
}
export const PI = 3.14159;
export default function subtract(a, b) {
return a - b;
}
// app.js
import subtract, { add, PI } from "./math.js";
Puedes tener varias exportaciones nombradas (named exports) por archivo, las cuales se importan por su nombre. Una exportación por defecto (default export) es un único valor principal. Los módulos tienen su propio scope, se evalúan una sola vez y permiten que los bundlers eliminen el código no utilizado mediante tree-shaking.
Clases
Las clases proporcionan una sintaxis clara para el código orientado a objetos, basada en el sistema de prototipos existente de JavaScript.
// user.js
class User {
#secret = "hidden"; // private field
constructor(name) {
this.name = name;
}
get greeting() {
return `Hello, ${this.name}`;
}
static create(name) {
return new User(name);
}
}
class Admin extends User {
constructor(name) {
super(name);
this.role = "admin";
}
}
extends y super gestionan la herencia, static define métodos en la propia clase y # marca campos que son verdaderamente privados. Internamente se siguen utilizando prototipos, pero la sintaxis es mucho más fácil de leer.
Otras características que vale la pena conocer
- Map y Set para colecciones con claves y valores únicos, con una mejor semántica que los objetos y arrays convencionales para estas tareas.
- for…of para iterar arrays, strings, maps, sets y cualquier iterable.
- Exponenciación con
**, por lo que2 ** 10reemplaza aMath.pow(2, 10). - Iteradores y generadores para secuencias perezosas (lazy sequences), iteraciones personalizadas y funciones pausables.
- Object.entries / fromEntries para convertir entre objetos y arrays de pares.
Mejores prácticas
- Usa
constpor defecto; utilizaletsolo cuando necesites reasignar. - Prefiere las arrow functions para los callbacks y funciones regulares para los métodos que requieran
this. - Aplica desestructuración en los parámetros para dejar explícita la estructura requerida.
- Usa el operador spread para actualizaciones inmutables en lugar de mutar datos compartidos.
- Recurre a
?.y??antes de escribir guardas anidadas. - Prefiere los métodos de array sobre los bucles manuales al transformar datos.
- Mantén los módulos pequeños y exporta la superficie mínima necesaria.
Errores comunes
- Asumir que
consthace que un objeto sea inmutable; solo evita la reasignación. - Usar una arrow function como método de un objeto y perder el contexto de
this. - Usar
||para valores por defecto cuando0o""son valores válidos; utiliza??. - Hacer spread de un solo nivel y esperar un clon profundo (deep clone).
- Mezclar
requireyimporten el mismo sistema de módulos sin entender la interoperabilidad. - Encadenar demasiados métodos de array creando un pipeline ilegible.
Próximos pasos
La sintaxis moderna es el vocabulario; el DOM y el JavaScript asíncrono son donde pones esos conocimientos en práctica. Una vez que las promesas y los módulos te resulten naturales, la Fetch API convertirá esas habilidades en aplicaciones reales.