JavaScript ES6
JavaScript 6, ECMAScript (ES6 o ES2015) es el estándar que sigue JavaScript desde Junio de 2015 y tuvo grandes mejoras. Hasta ese momento la versión de JS que estábamos usando en nuestros navegadores y Node.js, era la v5 del año 2011.
Principales novedades de ES6
Arrow function
Son abreviaciones de funciones utilizando el operador =>
Por ejemplo cuando queremos asignar un callback a una función, debemos escribir la función completa, supongamos que queremos obtener los cuadrados de los números contenidos en un arreglo:
var cuadrados = numeros.map(function(n) { return n * n; });
Con la nueva sintaxis podemos obtener el mismo resultado, pero de una forma más elegante:
var cuadrados = numeros.map(n => n * n);
También se soporta una función con varias sentencias usando las llaves {}, y si queremos asignar varios parámetros los rodeamos con paréntesis ()
numeros.forEach((n, i) => { if(n > 0) { console.log(i + " - " + n); } });
O asignar una función a una variable para reutilizarla después:
var func = x => x + 1; var num = func(5); // 6
Clases (classes)
Para crear una clase lo primero que debemos hacer es definir nuestro constructor, tarea que desempeñará una función que hará uso de la variable this como el objeto creado. Desde el momento en el que se defina la función podemos crear instancias de la clase para obtener nuevos objetos. El siguiente paso sería añadir métodos a nuestra clase que puedan ser utilizados por los objetos creados, y dado que en JavaScript todo es un objeto.
En este ejemplo definimos una clase con dos atributos y dos métodos:
class Rectangulo { constructor(base, altura) { this.base = base; this.altura = altura; } calcArea() { return this.base * this.altura; } } var r = new Rectangulo(5, 10); console.log(r.calcArea()); // 50
Herencia (inheritance)
Con la herencia podemos establecer una jerarquía de elementos y reutilizar según en que nivel se encuentra cada elemento. Ejemplo:
// Clase padre class Forma { constructor() { console.log("Soy una forma geométrica."); } gritar() { console.log("YEP!!"); } } // Clases hijas class Cuadrado extends Forma { constructor() { super(); console.log("Soy un cuadrado."); } } class Circulo extends Forma { constructor() { super(); console.log("Soy un círculo."); } } class Triangulo extends Forma { constructor() { super(); console.log("Soy un triángulo."); } }
Observa que la clase padre Forma muestra un mensaje en su constructor y tiene un método gritar(). Cada clase hija extiende a su clase padre, por lo que la clase Cuadrado será una mezcla de la clase Forma más la clase Cuadrado. El método especial super() llama al constructor de la clase padre, por lo que si creamos varios objetos, observa que funcionarán en cascada, mostrando primero el texto del constructor del padre, y luego el texto del constructor del hijo:
let cuadrado1 = new Cuadrado(); // 'Soy una forma geométrica.' // 'Soy un cuadrado.' cuadrado1.gritar(); // 'YEP!!' let triangulo1 = new Triangulo(); // 'Soy una forma geométrica.' // 'Soy un triángulo.' triangulo1.gritar(); // 'YEP!!'
Todas las clases hijas heredarán el método gritar(), ya que pertenece a la clase padre Forma y todas extienden de ella.
Template Strings
Son un tipo especial de cadena con formato, se definen con un par de caracteres back-tick (`) a diferencia de las cadenas normales que usan comillas sencillas o dobles.
var s1 = 'esta es una template string';
// Pueden contener valores var n = 5; var s2 = `El valor de n es ${n}`;
// Pueden abarcar múltiples líneas var s3 = `Esta es una cadena escrita en dos líneas`;
let y const
let indica que una variable solo va a estar definida en un bloque en particular, al terminar el bloque la variable deja de existir, esto es muy útil para evitar errores lógicos cuando alteramos una variable que no deberíamos.
function letTest() { if (true) { let x = 23; console.log(x); // 71 } console.log(x); // No existe x }
const por su parte previene que una variable declarada cambie de valor, convirtiéndola efectivamente en una constante. Siempre es recomendable usar constantes para valores que sabemos que no van a cambiar, así se evitan modificaciones inesperadas.
const a = 7; a = 5; // Error console.log(a);
Destructuring
Tenemos nuevas formas de asignar valores a Arrays y a Objetos. Veamos unos ejemplos:
let [a, b] = ["hola", "mundo"]; console.log(a); // "hola" console.log(b); // "mundo"
let obj = { nombre: "Luis", apellido: "Vera" }; let { nombre, apellido } = obj; console.log(nombre); // "Luis"
let foo = function() { return ["175", "75"]; }; let [estatura, peso] = foo(); console.log(estatura); // 175 console.log(peso); // 75
Valores por defecto
Podemos asignar valores por defecto a las variables que se pasan por parámetros en las funciones. Antes teníamos que comprobar si la variable ya tenía un valor. Ahora con ES6 se la podemos asignar según creemos la función. Ejemplo:
// ES5 function(valor) { valor = valor || "foo"; }
// ES6 function(valor = "foo") {...};
Módulos (module)
Llamamos a las funciones desde los propios scripts, sin tener que importarlos en el HTML, si usamos JavaScript en el navegador.
// File: lib/persona.js module "persona" { export function hello(nombre) { return nombre; } }
Y para importar en otro fichero: // File: app.js import { hola } from "persona"; let app = { foo: function() { hola("Mario"); } } export app;
Maps y Sets
A la hora de desarrollar algoritmos en JavaScript solo teníamos dos alternativas crear un objeto {} o un arreglo [] para almacenar datos, y aunque la mayoría de las veces es más que suficiente con ellos, puede presentarse el caso de que el rendimiento no es el adecuado. Los mapas (Map) son una estructura de datos que almacenan pares de llave (key) y valor (value), los conjuntos (Set) tienen la característica de no aceptar duplicados, y ambos permiten búsquedas eficientes cuando se tiene un gran volumen de información porque no guardan sus elementos ordenados por un índice, como ocurre con los arreglos.
En el siguiente ejemplo vemos el uso de Set, noten como se puede encadenar el método add para añadir nuevos elementos, si alguno se duplica es omitido y tiene un método has para revisar si existe un elemento dentro del conjunto.
// Sets var s = new Set(); // Añade 3 elementos, cadena1 se repite s.add("cadena1").add("cadena2").add("cadena1"); // El tamaño es 2 console.log(s.size === 2); // El conjunto no tiene la cadena hola console.log(s.has("hola"));
Un Map es similar, pero para añadir un elemento usamos el método set que acepta dos parámetros: la llave y su valor asociado. Se obtienen los valores con el método get.
// Maps var m = new Map(); // Añade la llave "hola" con el valor 42 m.set("hola", 42); // Añade la llave "a" con el valor 34 m.set("a", 34); // Obtiene el valor asociado a la llave "a" console.log(m.get("a")); // 34