Modern JavaScript

JavaScript Moderno (ES6+)

ES6 y las versiones posteriores transformaron JavaScript de un lenguaje de scripting peculiar en un placer al escribir. Aquí tienes las funcionalidades que usarás todos los días.

intermediate15 min readUpdated 15 sept 2026
js
// cart.js
const items = [
  { name: "Keyboard", price: 80, qty: 1 },
  { name: "Mouse", price: 40, qty: 2 },
];

const total = items
  .map(({ price, qty }) => price * qty)
  .reduce((sum, n) => sum + n, 0);

console.log(`Total: $${total}`);
Lanzado
Junio 2015
También conocido como
ES2015 / ES6
Desde entonces
Un lanzamiento cada año
Mayores logros
Scope, módulos, async
Adiciones clave
Arrow, destructuring, spread
Compatibilidad
Universal en navegadores modernos

Practico

Prueba los métodos de array modernos

Cambia los números y observa cómo se actualiza el total.

Prueba los métodos de array modernos

Cambia los números y observa cómo se actualiza el total.

Por que importa

Por qué importa el JavaScript moderno

Menos ceremonia

El destructuring, las abreviaciones y los template literals eliminan el código repetitivo para que la intención destaque sobre el ruido sintáctico.

Scope más seguro

let y const con scope de bloque reemplazan a var, eliminando toda una clase de errores de hoisting y globales accidentales.

Módulos reales

import y export le dieron a JavaScript un sistema de módulos estándar, haciendo que el intercambio de código y el tree-shaking sean naturales.

La imagen completa

Tres cambios que lo transformaron todo

ES6 no fue solo sintaxis nueva. Cambió la forma en que funciona el scope, cómo se organiza el código y cómo fluyen los datos a través de un programa.

Declaraciones

let, const, arrow

El scope de bloque y las funciones concisas cambiaron la forma en que se escribe y lee el código cotidiano.

Manejo de datos

Destructuring, spread

Descomponer valores y combinarlos se volvió expresivo en lugar de repetitivo.

Composición

Módulos, clases

Los módulos estándar y la sintaxis de clases facilitaron la organización y el intercambio de programas más grandes.

ES6+ de un vistazo

Las funcionalidades que usarás a diario

let & const

Bindings con scope de bloque que hacen que las variables sean predecibles.

Arrow functions

Sintaxis de función corta con this léxico, perfecta para callbacks.

Template literals

Cadenas multilínea e interpolación con backticks y ${}.

Destructuring

Desempaqueta arrays y objetos en variables en una sola expresión.

Spread & rest

Expande valores en un lugar o recógelos en uno solo, usando los mismos tres puntos.

Módulos

Divide el código en archivos con import y export en lugar de usar globales.

Una breve historia

El camino desde ES5 hasta hoy

  1. 2009

    ES5

    El strict mode, JSON y métodos de array como map y filter se convierten en la base.

    09
  2. 2015

    ES6 / ES2015

    La actualización más grande de la historia: let, const, arrows, clases, promises, módulos y más.

    15
  3. 2017

    async / await

    El código asíncrono finalmente se lee como si fuera código síncrono.

    17
  4. 2020

    Optional chaining

    ?. y ?? eliminan largas cadenas de comprobaciones defensivas de null.

    20
  5. Hoy

    Lanzamientos anuales

    TC39 publica una nueva edición del estándar compatible con versiones anteriores cada junio.

    Hoy

La guia completa

JavaScript Moderno (ES6+): Todo lo que necesitas saber

¿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 que 2 ** 10 reemplaza a Math.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 const por defecto; utiliza let solo 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 const hace 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 cuando 0 o "" son valores válidos; utiliza ??.
  • Hacer spread de un solo nivel y esperar un clon profundo (deep clone).
  • Mezclar require y import en 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.

Acceder a datos anidados

El optional chaining y el nullish coalescing reemplazan las cadenas de comprobaciones &&.

Preferir
const city =
  user?.address?.city ?? "Unknown";
Evitar
const city =
  user && user.address &&
  user.address.city
    ? user.address.city
    : "Unknown";

Transformar una lista

map y reduce expresan la intención y evitan el uso de variables acumuladoras manuales.

Preferir
const names = users
  .filter((u) => u.active)
  .map((u) => u.name);
Evitar
const names = [];
for (let i = 0; i < users.length; i++) {
  if (users[i].active) {
    names.push(users[i].name);
  }
}

Preguntas frecuentes

Preguntas frecuentes

Keep learning

Related topics from the roadmap.

$ comienza a aprender

Listo para aprender ES6+ Features?

Nuestro tutorial interactivo te guia a traves de ES6+ Features paso a paso — con quizzes y codigo real que puedes ejecutar en el navegador.