ES6 (ECMAScript 2015) fue la mayor actualización de JavaScript en su historia. Introdujo una sintaxis más moderna, patrones más limpios y herramientas que hoy usamos a diario. En este artículo repasamos las features más importantes con ejemplos prácticos.
let y const — Adiós al var
Antes de ES6, solo teníamos var para declarar variables. El problema era que var tiene scope de función, no de bloque, lo que causaba bugs inesperados.
// ❌ var — scope de función, se puede redeclarar
var nombre = "Ana";
var nombre = "Luis"; // No da error
// ✅ let — scope de bloque, reasignable
let edad = 25;
edad = 26; // OK
// ✅ const — scope de bloque, no reasignable
const PI = 3.14159;
// PI = 3; // ❌ TypeError: Assignment to constant variable
Diferencias clave
| Característica | var |
let |
const |
|---|---|---|---|
| Scope | Función | Bloque | Bloque |
| Redeclarable | Sí | No | No |
| Reasignable | Sí | Sí | No |
| Hoisting | Sí (inicializado como undefined) |
Sí (temporal dead zone) | Sí (temporal dead zone) |
Regla general: Usa
constpor defecto. Usaletsolo cuando necesites reasignar. Nunca usesvar.
Arrow Functions
Las arrow functions son una forma más concisa de escribir funciones. Además, no crean su propio this, lo que resuelve muchos problemas clásicos con callbacks.
// Función tradicional
function sumar(a, b) {
return a + b;
}
// Arrow function
const sumar = (a, b) => a + b;
// Con un solo parámetro, los paréntesis son opcionales
const doble = x => x * 2;
// Con cuerpo de múltiples líneas
const calcular = (a, b) => {
const resultado = a * b;
return resultado + 10;
};
El problema del this resuelto
// ❌ Antes de ES6 — this se pierde en callbacks
function Contador() {
this.count = 0;
setInterval(function () {
this.count++; // 'this' NO es el Contador, es window/undefined
}, 1000);
}
// ✅ Con arrow function — this se hereda del scope padre
function Contador() {
this.count = 0;
setInterval(() => {
this.count++; // 'this' SÍ es el Contador
}, 1000);
}
Template Literals
Los template literals permiten crear strings con interpolación de variables y multilínea usando backticks.
const nombre = "Carlos";
const edad = 30;
// ❌ Concatenación clásica
const saludo = "Hola, me llamo " + nombre + " y tengo " + edad + " años.";
// ✅ Template literal
const saludo = `Hola, me llamo ${nombre} y tengo ${edad} años.`;
// Multilínea
const html = `
<div class="card">
<h2>${nombre}</h2>
<p>Edad: ${edad}</p>
</div>
`;
// Expresiones dentro de ${}
const mensaje = `En 5 años tendré ${edad + 5} años.`;
Destructuring
El destructuring permite extraer valores de arrays y objetos en variables individuales de forma directa.
Destructuring de objetos
const usuario = {
nombre: "María",
edad: 28,
ciudad: "Madrid",
trabajo: "Desarrolladora"
};
// ❌ Sin destructuring
const nombre = usuario.nombre;
const edad = usuario.edad;
// ✅ Con destructuring
const { nombre, edad, ciudad } = usuario;
// Renombrar variables
const { nombre: userName, edad: userAge } = usuario;
// Valores por defecto
const { nombre, pais = "España" } = usuario;
// Destructuring anidado
const empresa = {
datos: {
nombre: "TechCorp",
direccion: { ciudad: "Barcelona", cp: "08001" }
}
};
const { datos: { direccion: { ciudad } } } = empresa;
Destructuring de arrays
const colores = ["rojo", "verde", "azul", "amarillo"];
// Extraer elementos
const [primero, segundo] = colores;
// primero → "rojo", segundo → "verde"
// Saltar elementos
const [, , tercero] = colores;
// tercero → "azul"
// Rest operator
const [cabeza, ...resto] = colores;
// cabeza → "rojo", resto → ["verde", "azul", "amarillo"]
// Intercambiar variables
let a = 1, b = 2;
[a, b] = [b, a];
// a → 2, b → 1
Spread y Rest Operators (...)
Los tres puntos (...) sirven para dos cosas: spread (expandir) y rest (recoger).
// SPREAD — expandir arrays/objetos
const nums = [1, 2, 3];
const masNums = [...nums, 4, 5]; // [1, 2, 3, 4, 5]
// Copiar un array (shallow copy)
const copia = [...nums];
// Merge de objetos
const base = { color: "azul", tamaño: "M" };
const extra = { tamaño: "L", peso: "200g" };
const merged = { ...base, ...extra };
// { color: "azul", tamaño: "L", peso: "200g" }
// REST — recoger argumentos
function sumarTodos(...numeros) {
return numeros.reduce((acc, n) => acc + n, 0);
}
sumarTodos(1, 2, 3, 4); // 10
Promesas y Async/Await
Las promesas son el mecanismo estándar para manejar operaciones asíncronas en JavaScript.
Promesas
// Crear una promesa
const obtenerDatos = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
const datos = { id: 1, nombre: "Producto" };
resolve(datos);
// reject(new Error("Fallo al obtener datos"));
}, 1000);
});
};
// Consumir la promesa
obtenerDatos()
.then(datos => console.log(datos))
.catch(error => console.error(error))
.finally(() => console.log("Operación completada"));
Async/Await (ES2017, pero complementa las promesas de ES6)
// Async/await hace que el código asíncrono parezca síncrono
async function cargarUsuario(id) {
try {
const response = await fetch(`/api/usuarios/${id}`);
const usuario = await response.json();
return usuario;
} catch (error) {
console.error("Error cargando usuario:", error);
}
}
// Ejecutar varias promesas en paralelo
async function cargarTodo() {
const [usuarios, productos] = await Promise.all([
fetch("/api/usuarios").then(r => r.json()),
fetch("/api/productos").then(r => r.json())
]);
console.log(usuarios, productos);
}
Módulos (import / export)
ES6 introdujo un sistema de módulos nativo para JavaScript, permitiendo organizar el código en archivos separados.
// 📁 utils/math.js
export const PI = 3.14159;
export function sumar(a, b) {
return a + b;
}
export default function multiplicar(a, b) {
return a * b;
}
// 📁 app.js
import multiplicar, { PI, sumar } from "./utils/math.js";
console.log(sumar(2, 3)); // 5
console.log(multiplicar(4, 5)); // 20
console.log(PI); // 3.14159
Tipos de export/import
// Named exports — puedes tener varios por archivo
export const nombre = "valor";
export function fn() {}
// Default export — solo uno por archivo
export default function principal() {}
// Import con alias
import { sumar as add } from "./math.js";
// Import todo el módulo
import * as MathUtils from "./math.js";
MathUtils.sumar(1, 2);
Clases
ES6 introdujo la sintaxis class como azúcar sintáctico sobre el sistema de prototipos de JavaScript.
class Animal {
constructor(nombre, sonido) {
this.nombre = nombre;
this.sonido = sonido;
}
hablar() {
return `${this.nombre} hace ${this.sonido}`;
}
// Getter
get info() {
return `${this.nombre} (${this.sonido})`;
}
// Método estático
static crearPerro() {
return new Animal("Perro", "Guau");
}
}
// Herencia
class Gato extends Animal {
constructor(nombre, color) {
super(nombre, "Miau");
this.color = color;
}
hablar() {
return `${super.hablar()} 🐱`;
}
}
const michi = new Gato("Luna", "negro");
michi.hablar(); // "Luna hace Miau 🐱"
Otras features importantes
Map y Set
// Map — diccionario con claves de cualquier tipo
const mapa = new Map();
mapa.set("nombre", "Ana");
mapa.set(42, "la respuesta");
mapa.set(true, "booleano como clave");
mapa.get("nombre"); // "Ana"
mapa.size; // 3
// Set — colección de valores únicos
const unicos = new Set([1, 2, 2, 3, 3, 3]);
// Set {1, 2, 3}
unicos.add(4);
unicos.has(2); // true
unicos.delete(1);
Símbolos
// Symbol — identificador único e inmutable
const id = Symbol("id");
const usuario = {
[id]: 123,
nombre: "Pedro"
};
usuario[id]; // 123
// El símbolo no aparece en for...in ni Object.keys()
Valores por defecto en parámetros
function crearUsuario(nombre, rol = "usuario", activo = true) {
return { nombre, rol, activo };
}
crearUsuario("Ana"); // { nombre: "Ana", rol: "usuario", activo: true }
crearUsuario("Luis", "admin"); // { nombre: "Luis", rol: "admin", activo: true }
Shorthand en objetos
const nombre = "Sara";
const edad = 25;
// ❌ Antes
const persona = { nombre: nombre, edad: edad };
// ✅ ES6 shorthand
const persona = { nombre, edad };
// Métodos shorthand
const calc = {
sumar(a, b) { return a + b; },
restar(a, b) { return a - b; }
};
Conclusión
ES6 transformó JavaScript de un lenguaje con muchas limitaciones a uno moderno y expresivo. Estas features no son solo azúcar sintáctico — cambian la forma en la que estructuramos, organizamos y pensamos nuestro código.
Si aún no estás usando todas estas características, el mejor momento para empezar es ahora. La mayoría de navegadores modernos y Node.js las soportan nativamente, así que no hay excusas.
¡Happy coding!