Webcomponents y Polymer 2. ES6 y novedades. Parte 2

Conceptos nuevos de ES6 para enterder mejor Polymer 2

Con este pequeño repaso voy a explicar ciertos conceptos sobre algunas de las mejoras que trae ES6 y que se aplican no solo en Polymer 2 sino a Javascript nativo, mejorando nuestro código.

El API de Webcomponent esta desarrollado encima de ES6, y ESx es la forma abreviada de llamar a EMACScript. Para profundizar sobre este tema puedes visitar esta web.

A continuación puedes comprobar la compatibilidad de ES6 en los navegadores:

Para navegadores antiguos existe un paso intermedio que es la transpilación. Aunque el soporte es generalizado en navegadores modernos estamos obligados a
transpilar para tener total compatibilidad con todos los navegadores. Para realizar esa transpilación podemos usar librerías como BabelJS.

Usando Polymer CLI podemos usar el siguiente comando ‘polymer build’. Si la aplicación está escrita completamente en Polymer y no utiliza otras herramientas o frameworks, simplemente puede usar Polymer CLI para construir su aplicación. Puedes configurar tu compilación o crear varias compilaciones escribiendo un archivo de configuración de polymer.json.

Declaración de variables

En ES5 todas las variables se declaran con var, en ES6 se pueden usar otras palabras reservadas para la definición de variables:

var: La declaración clásica, el ámbito es la función o puede ser global si esta fuera de la función o módulo.
let: Es una variable local parecida a var, solo que cuando se define dentro de un bloque el ámbito es el bloque donde se define. Si no existe ningún bloque funciona como var.
const: Crea una constante, el ámbito es el bloque y funciona como let pero no se puede modificar.

Clases en Javascript

Las clases de Javascript son introducidas en el ECMAScript 2015 (ES6) y son una mejora sintáctica sobre la herencia basada en prototipos de JavaScript.

La sintaxis de las clases NO introduce un nuevo modelo de herencia orientada a objetos a JavaScript. Las clases de JavaScript proveen una sintaxis mucho más clara y simple para crear objetos y lidiar con la herencia.

Dentro de las clases no se pueden declarar propiedades. Para definir esas propiedades podemos usar el constructor declarándolas al vuelo o usar cualquier otro método.

Ejemplo para definir y usar una clase en Javascript:

class Persona {
  constructor(nombre, edad) {
    this.nombre = nombre;
    this.edad = edad;
  }
  getInfo() {
    return this.nombre + ' / ' + this.edad;
  }
}
let p1 = new Persona('Ivan',40)
p1.getInfo();

Los métodos estáticos, son llamados métodos de clase ya que no pertenecen al objeto sino a la clase. Un ejemplo de un método de clase puede ser el siguiente:

class Persona {
  constructor(nombre, edad) {
    this.nombre = nombre;
    this.edad = edad;
  }
  getInfo() {
    return this.nombre + ' / ' + this.edad;
  }
  static help() {
    return 'En esta clase se define la Persona y tiene un método llamado getInfo() que devuelve el nombre y la edad usandos en el constructor. Ejemplo de uso: new Persona("nombre",1)';
  }
}
let p1 = new Persona('Ivan',40)
p1.getInfo();
console.log(Persona.help());

Propiedades estáticas usando getters y setters

Las propiedades estáticas las declaramos usando ES5 ya que las clases de ES6 no permiten propiedades dentro de la clases.

Para poder definir las propiedades usaremos los getters  y setters.  A continuación un ejemplo:

class Persona {
  constructor(nombre, edad) {
    this.nombre = nombre;
    this.edad = edad;
  }
  getInfo() {
    return this.nombre + ' / ' + this.edad;
  }
  static help() {
    return 'En esta clase se define la Persona y tiene un método llamado getInfo() que devuelve el nombre y la edad usandos en el constructor. Ejemplo de uso: new Persona("nombre",1)';
  }
  get getNombre() {
    return this.nombre;
  }
  get getEdad() {
    return this.edad;
  }
  set setNombre(v) {
    this.nombre = v;
  }
  set setEdad(v) {
    this.edad = v;
  }
}

var p1 = new Persona('a',1);
p1.getEdad; -- > 1
p1.getNombre; --> "a"
p1.setEdad = 2; --> 2
p1.getEdad; --> 2

Herencia en Javascript

Cuando has trabajado con lenguajes como JAVA , C++, C# o PHP, el concepto de objetos, clases, herencias es bien conocido, pero en JavaScript provoca cierta confusión  por ser dinámico y no proporcionar una implementación de clases en sí mismo, ya que la palabra clave class se introdujo pero sólo para endulzar la sintaxis, ya que JavaScript sigue estando basado en prototipos.

En lo que a herencia se refiere, JavaScript sólo tiene una estructura: objetos. Cada objeto tiene una propiedad privada (referida como su [[Prototype]]) que mantiene un enlace a otro objeto llamado su prototipo.

Ese objeto prototipo tiene su propio prototipo, y así sucesivamente hasta que se alcanza un objeto cuyo prototipo es null. Por definición, null no tiene prototipo y actúa como el enlace final de esta cadena de prototipos.

Casi todos los objetos en JavaScript son instancias de object que se sitúa a la cabeza de la cadena de prototipos.

A pesar de que a menudo esto se considera como una de las principales debilidades de JavaScript, el modelo de herencia de prototipos es de hecho más potente que el modelo clásico.

class Persona {
  constructor(nombre, edad) {
    this.nombre = nombre;
    this.edad = edad;
  }
  getInfo() {
    return this.nombre + ' / ' + this.edad;
  }
  static help() {
    return 'En esta clase se define la Persona y tiene un método llamado getInfo() que devuelve el nombre y la edad usandos en el constructor. Ejemplo de uso: new Persona("nombre",1)';
  }
  get getNombre() {
    return this.nombre;
  }
  get getEdad() {
    return this.edad;
  }
  set setNombre(v) {
    this.nombre = v;
  }
  set setEdad(v) {
    this.edad = v;
  }
}

class Personal extends Persona {
  constructor(nombre, edad, sexo, estadoCivil, trabajo) {
    super(nombre, edad);
    this.sexo = sexo;
    this.estadoCivil = estadoCivil;
    this.trabajo = trabajo;
  }
  getInfo() {
    console.log(super.getInfo() + ' / ' + this.sexo + ' / ' + this.estadoCivil + ' / ' + this.trabajo);
  }
}

let p1 = new Personal('a',1,'h','soltero',true)
p1; --> Personal {nombre: "a", edad: 1, sexo: "h", estadoCivil: "soltero", trabajo: true}
p1.getInfo(); --> super.getInfo() [a / 1] personal.getInfo() [ / h / soltero / true]

Promesas y Javascript Asíncrono

Una Promise es un objeto que representa la terminación de  una operación asíncrona, ya sea correcta o fallida.

Una promesa puede ser creada usando su constructor,  sin embargo, la mayoría de la gente son consumidores de promesas ya creadas devueltas desde funciones.

Básicamente una promesa es un objeto devuelto en el cual defines un callback de existo(s) o fallo(s).

Por ejemplo, en vez de una función del viejo estilo que espera dos funciones callback, y llama a una de ellas en caso de terminación o fallo:

function sumaAsincrona(a, b) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      (Math.floor(Math.random() * a + b) + 1) > ((a + b) / 2) ? resolve('OK') : reject('fail');
    },3000);
  });
}
sumaAsincrona(4, 4)
  .then(function(v) {
    console.log("OK: " + v);
  })
  .catch(function(v) {
    console.log("ERR: " + v);
  });

Arrow functions y sus ventajas

Las arrow function (funciones flecha) tiene una sintaxis más corta que una función convencional y no vincula sus propios this, arguments, super o new.target. Las arrow function siempre son anónimas, no relacionadas con métodos y no pueden ser usadas como constructores.

La inclusión de las arrow function se vieron influenciadas por dos factores:

  • sintaxis reducida
  • this no vinculable.

Antes de las arrow function, cada nueva función definía su propio valor this, Lo cual resultaba molesto cuando se intentaba aplicar programación orientada a objetos.

Aquí algunos ejemplos de funciones convencionales frente a arrow function:

ARROW FUNCTION

// un solo parámetro
let potencia = val => val * val;

// multiples parámetros
let suma = (a,b) => a + b;

// multiples lineas
let datos = (nombre, edad, sexo) => {
  let s = sexo === 'mujer' ? 'a' : '';
  return 'Tu nombre es ' + nombre + ' y tienes ' + edad + ' años. Eres un' + s + ' ' + sexo;
};

STANDARD FUNCTION

// un solo parámetro
let potencia = function(val) {
  return val * val;
}

// multiples parámetros
let suma = function(a,b) {
  return a + b;
}

// multiples lineas
let datos = function(nombre, edad, sexo) {
  let s = sexo === 'mujer' ? 'a' : '';
  return 'Tu nombre es ' + nombre + ' y tienes ' + edad + ' años. Eres un' + s + ' ' + sexo;
};

Templates String o como crear plantillas

Los template strings son literales de texto que habilitan el uso de expresiones incrustadas. Es posible utilizar cadenas de texto de más de una línea, y funcionalidades de interpolación de cadenas de texto con ellas.

Las plantillas de cadena de texto se delimitan con el caracter de comillas o tildes invertidas (` `), en lugar de las comillas simples o dobles. Las plantillas de cadena de texto pueden contener marcadores, indentificados por el signo de dolar y envueltos en llaves ${expresion}.

Las expresiones contenidas en los marcadores junto con el texto entre ellas son enviados como argumentos a una función. La función por defecto simplemente concatena las partes para formar una única cadena de texto.

Unos ejemplos para entenderlo mejor:

let ciudad = 'Madrid';
let habitantes = '3.166.000';
let year = 2016;

let frase = `La ciudad de ${ciudad} tiene ${habitantes} personas censadas en el año ${year}`;