ES6

He estado leyendo sobre las novedades de ES6 y aquí va un pequeño recopilatorio de algunas de ellas.

Classes

Para comenzar aquello de lo que tanto se hablaba cuando salió. Lo primero que hay que decir es que es solo maquillaje para hacer la vida mas fácil en algunos aspectos y escribir menos. Aunque parezca una clase, se seguirá comportando como una simple función.

Como ventaja, al utilizar la sintaxis de clase, puede que sea mas simple tratar con la herencia de prototipos de Javascript.

class Car {
  constructor(brand, model, year) {
    this.brand = brand;
    this.model = model;
    this.year = year;
  }

  printOut() {
    console.log(`${this.brand} ${this.model} - ${this.year}`);
  }
}

let myCar = new Car('Daewoo', 'Kalos', 2005);
console.log(myCar.printOut()); //Daewoo Kalos - 2005
typeof myCar; //object
typeof Car; //function

Las clases pueden ser anónimas, asignando su definición a una variable, después usaremos esta variable para crear una nueva instancia de la clase.

var Car = class {
  constructor(brand, model, year) {
    this.brand = brand;
    this.model = model;
    this.year = year;
  }

  printOut() {
    console.log(`${this.brand} ${this.model} - ${this.year}`);
  }
};

var myCar = new Car();

En ES6 hay herencia, y puede ser útil para acceder al prototipo cómodamente.

class Amphibious {
  constructor(type = 'river') {
    this.type = type;
  }

  crossRiver() {
    console.log('I am swimming');
  }
}

class Car extends Amphibious {
  constructor(type, brand, model, year) {
    super(type);
    this.brand = brand;
    this.model = model;
    this.year = year;
  }

  printOut() {
    console.log(`${this.brand} ${this.model} - ${this.year}`);
  }
}

var car = new Car('Alfa Romeo', 'Giulia', 1998);
console.log(car.printOut());
console.log(car.crossRiver());

const

Como su nombre sugiere, se trata de una constante, es decir, un valor que no puede cambiar a lo largo de la ejecución de nuestro programa una vez que ha sido definido, al contrario que ocurre con las variables.

A día de hoy esto es así al menos en Chrome y Firefox, sin embargo Safari las trata como simples variables. Son por lo tanto útiles como en cualquier lenguaje, para albergar valores inmutables.

const MAX_CHILD_AGE = 18;
//Si intento redefinirla, obtendré un error
const MAX_CHILD_AGE = 16;
//Uncaught TypeError: Identifier 'MAX_CHILD_AGE' has already been declared(…)

let

Esta novedad me gusta mucho, porque permite controlar el scope de nuestras variables de una forma precisa. Al declarar una variable con let lo que ocurre es que esa variable solo sera modificable o accesible en el scope en el que ha sido definida: bloque, declaración o expresión donde se usa.

Sin embargo con var se puede acceder a la variable en el scope exterior a donde la estemos usando. Con un ejemplo siempre es mas claro.

var color = "red";
console.log(color);
if (true) {
  var color = "blue";
  console.log(color);
}
console.log(color);
let shape = "square";
console.log(shape);
if (true) {
  let shape = "circle";
  console.log(shape);
}
console.log(shape);

Generators

Me parecen bastante divertidos. Son unas funciones especiales, que nos permiten ejecutarlas por partes y parar o hacer continuar la ejecución. Las reconoceremos porque tiene un asterisco junto a la palabra function y contienen el termino yield.

De alguna forma se trata de una factoría de iteradores cuyo estado es controlado por una función. Por lo tanto nos puede ayudar a crear funciones asíncronas.

Un objeto es un iterador cuando sabe como acceder a los elementos de una colección, mientras mantiene un registro de su posición actual dentro de esa secuencia. En JavaScript un iterador es un objeto que proporciona un método next() que devuelve el siguiente elemento en la secuencia. Este método devuelve un objeto con dos propiedades: done y value. Ver mas sobre ello en MDN.

 

//GENERATORS
var numberGenerator = function* numberGenerator() {
  var number = 0;
  yield number++;
  yield number++;
  yield number++;
  yield number++;
  yield number++;
  return;
}();
console.log(numberGenerator.next());
console.log(numberGenerator.next());
console.log(numberGenerator.next());
console.log(numberGenerator.next());
console.log(numberGenerator.next());
console.log(numberGenerator.next());
//{ value: 0, done: false }
//{ value: 1, done: false }
//{ value: 2, done: false }
//{ value: 3, done: false }
//{ value: 4, done: false }
//{ value: undefined, done: true }

next() puede recibir un parámetro, que sera considerado en la función como el resultado del ultimo yield.

Default function parameters

Puede parecer increíble, pero aun no existían. Estamos acostumbrados a verlos en otros lenguajes como PHP. Tan simple como:

function takeCare(takeIt = 'easy') {
  console.log(takeIt);
};
takeCare(); //easy

Template literals

Parece ser que tenemos una forma de decir adiós al infierno de las dobles comillas y las concatenaciones con el símbolo +.

En general, incluir información compleja es mas sencillo. Veamos algunos ejemplos.

//Concatenar con variables
var animal = 'cats';
var sentenceES5 = 'She said ' + animal + ' are independent';
var sentenceES6 = `She said ${animal} are independent`;
console.log(sentenceES5);
console.log(sentenceES6);

//Saltos de linea
var sentenceES5 = 'She said ' + animal + '\nbreak the line';
var sentenceES6 = `She said ${animal}
break the line`;
console.log(sentenceES5);
console.log(sentenceES6);

//Concatenar con operaciones
var sentenceES5 = 'She said ' + animal + ' break the line ' + (1 + 1) + ' times';
var sentenceES6 = `She said ${animal} break the line ${1 + 1} times`;
console.log(sentenceES5);
console.log(sentenceES6);

//Llamar a funciones
var sentenceES5 = animal.toUpperCase() + ' are evil';
var sentenceES6 = `${animal.toUpperCase()} are evil`;
console.log(sentenceES5);
console.log(sentenceES6);

Arrow functions

Lo primero que hay que decir es que las arrow functions vienen a resolver un problema de diseño de javascript: la palabra this en una función sin scope, se refiere al objeto window. Es decir que las arrow functions vinculan contextualmente this a la función, lo que es de esperar o lo que lógicamente un programador podría esperar, como ocurre por ejemplo en un objeto:

var car = {
  color: "red",
  wheels: ['RF', 'LF', 'RR', 'LR'],
  printWheels: function () {
    this.wheels.forEach(function (wheel) {
      console.log(wheel + ' in a ' + this.color + ' car');
    });
  },
};
car.printWheels();
//this.color es undefined. Si anadimos:
this.color = "blue"
car.printWheels()
//RF in a blue car
//LF in a blue car
//RR in a blue car
//LR in a blue car

Si, es una de esas extravagancias de javascript, como tantas otras, que los programadores han resulto de forma imaginativa en versiones anteriores, por ejemplo creando una variable self a la que se asigna this. De forma que el scope en el momento de definir el objeto esté disponible al ejecutarlo.

Veamos ahora como this se refiere al contexto en el que se encuentra, usando arrow functions.

var car = {
  color: "red",
  wheels: ['RF', 'LF', 'RR', 'LR'],
  printWheels() {
    this.wheels.forEach((wheel) => {
      console.log(wheel + ' in a ' + this.color + ' car');
    });
  }
};
car.printWheels();
//RF in a red car
//LF in a red car
//RR in a red car
//LR in a red car

Spread Operator

Este operador, usado antes de un array, sirve para extenderlo, por ejemplo para incluir los elementos de un array dentro de otro sin aumentar las dimensiones, o para usar los elementos de un array como argumentos de una función. Siempre es mejor ver el código:

//crea un array unidimensional
var animals = ['owl', 'camel', 'pinguin', 'otter', 'beaver', 'ox'];
var flowers = ['Water lily', 'Hibiscus', 'Bird of paradise'];
var things = ['car', ...animals, ...flowers, 'computer'];
console.log(things);
//pasar argumentos de funciones
var numbers = [2, 6, 9, 10];
console.log(Math.min(...numbers));
//otro ejemplo
var sumArgs = (a, b, c) => {
  return a + b + c
};
console.log(sumArgs(...numbers));

Destructuring assignment

Nos ayuda a asignar los elementos de un array a variables rápidamente.

//ES5
var myArray = ['pear','apple','strawberry'];
console.log(myArray[0]);

//usando asignación por destructuring:
var [pera, manzana, fresa] = myArray;
console.log(pera);
console.log(manzana);
console.log(fresa);

//otros ejemplos
var[primero, ...elResto] = myArray;
var[primero,,tercero] = myArray;

//Con objetos también funciona:
var post = {
  author : 'Pepe',
  title : 'Ecmascript 6'
};
var {author, title} = post;
console.log(author);
console.log(title);

En este caso hay que tener en cuenta que en lugar de “[” hemos usado “{“.

Ademas como nombre de las variables no podemos poner cualquier cosa, sino el nombre de la propiedad que queremos recuperar, a no ser que lo especifiquemos :

var {author: customName, title} = post;

Aquí, customName es el nombre que queremos darle, y author es el nombre de la propiedad del objeto post que queremos recuperar.

Y hasta aquí he llegado en este post, por supuesto hay muchísimo mas, espero tratar otros asuntos de ES6 en próximamente.