ECMAScript 6

images/es6.png

ECMAScript 2015 (6ta edición) es la versión actual de la especificación del lenguaje ECMAScript, conocida simplemente como ES6. El nombre clave es ES.next o Harmony. El primer borrador de la especificación (basada en ECMAScript 5.1) fue publicada el 12 de Julio de 2011 como ES.next, en Agosto de 2014 el borrador de la especificación fue detenido respecto de nuevas características y pasó por un período de estabilización y soluciones de bugs, finalmente, el ECMA-262 edición 6 fue oficialmente aprobada y publicada en Junio 17 de 2015 por el ECMA General Assembly. También aparecerá como el ISO/IEC 16262:2016. - ECMAScript 6 support in Mozilla

Puedes encontrar una tabla comparativa del nivel de soporte de ES6 en distintos entornos de ejecución, incluyendo los principales navegadores web (Desktop browsers), en http://kangax.github.io/compat-table/es6/.

Características

A continuación se plantean solo algunas pocas características de ECMAScript 6 que es posible adoptar en cualquiera de los principales navegadores web.

Práctica 01

  1. Crea el directorio $HOME/www/es601, accede a él y crea el archivo index.html con el siguiente contenido:

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="UTF-8">
        <title>es6 - 01</title>
      </head>
      <body>
        <h1>es6 - 01</h1>
        <canvas id="dona-canvas" width="400" height="200"></canvas>
        <script src="js/main.js" type="module"></script>
      </body>
    </html>
    
  2. Crea los directorios js, js/lib, js/lib/e, js/lib/f y js/lib/f/g:

    alumno@servidor:~/www/es601$ mkdir -p js js/lib js/lib/e js/lib/f js/lib/f/g
    
  3. Crea los siguientes archivos con su correspondiente contenido:

    • js/main.js

      import {imprimir_saludo as moduloa_saludar, modificar_estado as moduloa_modificar} from "./moduloa.js";
      import {imprimir_saludo as moduloc_saludar, modificar_estado as moduloc_modificar} from "./moduloc.js";
      
      let nombre = "Módulo Main";
      let identificacion = "Soy " + nombre;
      
      const estado = {};
      estado[nombre] = 10;
      
      let saludo = "¡Hola!. " + identificacion + "."
      console.log(saludo);
      
      moduloa_saludar(nombre)
      moduloa_modificar(estado);
      
      moduloc_saludar(nombre);
      moduloc_modificar(estado);
      
      console.table(estado);
      
      console.log("¡Adios!. " + "Se despide " + nombre + ".");
      
    • js/moduloa.js

      export {imprimir_saludo, modificar_estado};
      
      import {imprimir_saludo as modulob_saludar, modificar_estado as modulob_modificar} from "./modulob.js";
      
      let nombre = "Módulo A";
      let identificacion = "Soy " + nombre;
      
      let imprimir_saludo = function(sujeto) {
          let saludo = "¡Hola " + sujeto + "!. " + identificacion + "."
          console.log(saludo);
          modulob_saludar(nombre);
          imprimir_despedida(sujeto);
      };
      
      let imprimir_despedida = function(sujeto) {
          console.log("¡Adios " + sujeto + "!. " + "Se despide " + nombre + ".");
      };
      
      let modificar_estado = function(estado) {
          if (estado[nombre] === undefined) {
              estado[nombre] = 20;
          } else {
              estado[nombre] = 5 * estado[nombre];
          }
          modulob_modificar(estado);
      };
      
    • js/modulob.js

      export {imprimir_saludo, modificar_estado};
      
      let nombre = "Módulo B";
      let identificacion = "Soy " + nombre;
      
      let imprimir_saludo = function(sujeto) {
          let saludo = "¡Hola " + sujeto + "!. " + identificacion + "."
          console.log(saludo);
          imprimir_despedida(sujeto);
      };
      
      let imprimir_despedida = function(sujeto) {
          console.log("¡Adios " + sujeto + "!. " + "Se despide " + nombre + ".");
      };
      
      let modificar_estado = function(estado) {
          if (estado[nombre] === undefined) {
              estado[nombre] = 30;
          } else {
              estado[nombre] = 3 * estado[nombre];
          }
      };
      
    • js/moduloc.js

      export {imprimir_saludo, modificar_estado};
      
      import {imprimir_saludo as modulod_saludar, modificar_estado as modulod_modificar} from "./lib/modulod.js";
      
      let nombre = "Módulo C";
      let identificacion = "Soy " + nombre;
      
      let imprimir_saludo = function(sujeto) {
          let saludo = "¡Hola " + sujeto + "!. " + identificacion + "."
          console.log(saludo);
          modulod_saludar(nombre);
          imprimir_despedida(sujeto);
      };
      
      let imprimir_despedida = function(sujeto) {
          console.log("¡Adios " + sujeto + "!. " + "Se despide " + nombre + ".");
      };
      
      let modificar_estado = function(estado) {
          estado[nombre] = 40;
          modulod_modificar(estado);
      };
      
    • js/lib/modulod.js

      export {imprimir_saludo, modificar_estado};
      
      import {imprimir_saludo as moduloe_saludar, modificar_estado as moduloe_modificar} from "./e/moduloe.js";
      import "./Chart.js";
      
      let nombre = "Módulo D";
      let identificacion = "Soy " + nombre;
      
      let imprimir_saludo = function(sujeto) {
          let saludo = "¡Hola " + sujeto + "!. " + identificacion + "."
          console.log(saludo);
          usar_modulo_chart();
          moduloe_saludar(nombre);
          imprimir_despedida(sujeto);
      };
      
      let imprimir_despedida = function(sujeto) {
          console.log("¡Adios " + sujeto + "!. " + "Se despide " + nombre + ".");
      };
      
      let usar_modulo_chart = function() {
          /*
           * Librería: http://www.chartjs.org
           * Fuente: http://www.chartjs.org/samples/latest/charts/doughnut.html
           */
          let randomScalingFactor = function() {
              return Math.round(Math.random() * 100);
          };
      
          let dona_canvas = document.getElementById("dona-canvas");
          let dona_configuracion = {
              type: 'doughnut',
              data: {
                  datasets: [{
                      data: [
                          randomScalingFactor(),
                          randomScalingFactor(),
                          randomScalingFactor(),
                          randomScalingFactor(),
                          randomScalingFactor(),
                      ],
                      backgroundColor: [
                          "red",
                          "orange",
                          "yellow",
                          "green",
                          "blue",
                      ],
                      label: 'Dataset 1'
                  }],
                  labels: [
                      'Red',
                      'Orange',
                      'Yellow',
                      'Green',
                      'Blue'
                  ]
              },
              options: {
                  responsive: false,
                  legend: {
                      position: 'top',
                  },
                  title: {
                      display: true,
                      text: 'Chart.js Doughnut Chart'
                  },
                  animation: {
                      animateScale: true,
                      animateRotate: true
                  }
              }
          };
          let dona_grafica = new Chart(dona_canvas, dona_configuracion);
      };
      
      let modificar_estado = function(estado) {
          estado[nombre] = 50;
          moduloe_modificar(estado);
      };
      
    • js/lib/e/moduloe.js

      export {imprimir_saludo, modificar_estado};
      
      import {imprimir_saludo as modulof_saludar, modificar_estado as modulof_modificar} from "../f/modulof.js";
      import {modificar_estado as moduloa_modificar} from "../../moduloa.js";
      
      let nombre = "Módulo E";
      let identificacion = "Soy " + nombre;
      
      let imprimir_saludo = function(sujeto) {
          let saludo = "¡Hola " + sujeto + "!. " + identificacion + "."
          console.log(saludo);
          modulof_saludar(nombre);
          imprimir_despedida(sujeto);
      };
      
      let imprimir_despedida = function(sujeto) {
          console.log("¡Adios " + sujeto + "!. " + "Se despide " + nombre + ".");
      };
      
      let modificar_estado = function(estado) {
          estado[nombre] = 60;
          modulof_modificar(estado);
          moduloa_modificar(estado);
      };
      
    • js/lib/f/modulof.js

      export {imprimir_saludo, modificar_estado};
      
      import {imprimir_saludo as modulog_saludar, modificar_estado as moduloe_modificar} from "./g/modulog.js";
      import {modificar_estado as modulob_modificar} from "../../modulob.js";
      
      let nombre = "Módulo F";
      let identificacion = "Soy " + nombre;
      
      let imprimir_saludo = function(sujeto) {
          let saludo = "¡Hola " + sujeto + "!. " + identificacion + "."
          console.log(saludo);
          modulog_saludar(nombre);
          imprimir_despedida(sujeto);
      };
      
      let imprimir_despedida = function(sujeto) {
          console.log("¡Adios " + sujeto + "!. " + "Se despide " + nombre + ".");
      };
      
      let modificar_estado = function(estado) {
          estado[nombre] = 70;
          moduloe_modificar(estado);
          modulob_modificar(estado);
      };
      
    • js/lib/f/g/modulog.js

      export {imprimir_saludo, modificar_estado};
      
      let nombre = "Módulo G";
      let identificacion = "Soy " + nombre;
      
      let imprimir_saludo = function(sujeto) {
          let saludo = "¡Hola " + sujeto + "!. " + identificacion + "."
          console.log(saludo);
          imprimir_despedida(sujeto);
      };
      
      let imprimir_despedida = function(sujeto) {
          console.log("¡Adios " + sujeto + "!. " + "Se despide " + nombre + ".");
      };
      
      let modificar_estado = function(estado) {
          estado[nombre] = 80;
      };
      
  4. Descarga la librería Chart.js:

     alumno@servidor:~/www/es601 $ wget https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.js -P js/lib
    

    Hasta este punto tendrás la siguiente estructura en $HOME/www/es601:

     alumno@servidor:~/www/es601 $ pwd && tree
     /home/alumno/www/es601
     .
     ├── index.html
     └── js
         ├── lib
         │   ├── Chart.js
         │   ├── e
         │   │   └── moduloe.js
         │   ├── f
         │   │   ├── g
         │   │   │   └── modulog.js
         │   │   └── modulof.js
         │   └── modulod.js
         ├── main.js
         ├── moduloa.js
         ├── modulob.js
         └── moduloc.js
    
     5 directories, 10 files
    
  5. Inicia el servidor web y accede a él poniendo atención a lo impreso en Console:

    images/02.png

Observaciones:

Práctica 02

  1. Crea el directorio $HOME/www/es602, accede a él y crea el archivo index.html con el siguiente contenido:

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title>es6 - 02</title>
        </head>
        <body>
            <h1>es6 - 02</h1>
            <script type="module" src="js/main.js"></script>
        </body>
    </html>
    
  2. Crea los directorios js, js/clases y js/lib:

    alumno@servidor:~/www/es602$ mkdir -p js js/clases js/lib
    
  3. Crea los siguientes archivos con su correspondiente contenido:

    • js/main.js

      /*
       * Se requiere (`import`) de todo aquello expuesto (`export`) por el módulo 'es6.js'.
       * Localmente, aquello expuesto (`export`) por 'es6.js', es precedido por el sobrenombre (`as`) 'es6'.
       */
      
      import * as es6 from "./lib/es6.js";
      
      let main = function() {
          console.log("Iniciando...");
      
          console.group("Uso de let y const");
          es6.uso_de_let_y_const();
          console.groupEnd();
      
          console.group("Uso de `template string` o `template literals`");
          es6.uso_de_template_string_literal("MUNDO");
          console.groupEnd();
      
          console.group("Uso de 'arrow function' o 'función flecha'");
          es6.uso_de_arrow_function();
          console.groupEnd();
      
          console.group("Uso de argumentos opcionales");
          es6.uso_de_argumentos_opcionales("MUNDO");
          es6.uso_de_argumentos_opcionales("MUNDO", "PLANETA");
          es6.uso_de_argumentos_opcionales("MUNDO", "PLANETA", "TIERRA");
          console.groupEnd();
      
          console.group("Uso de desestructuración");
          es6.uso_de_desestructuracion(-15);
          console.groupEnd();
      
          console.group("Uso de maps y sets");
          es6.uso_de_maps_y_sets(-3, 3);
          console.groupEnd();
      
          console.group("Uso de clases");
          es6.uso_de_clases();
          console.groupEnd();
      
          console.log("Terminado");
      };
      
      main();
      
    • js/lib/es6.js

      import {ClaseA} from "../clases/clasea.js";
      import {ClaseB} from "../clases/claseb.js";
      import {ClaseC} from "../clases/clasec.js";
      
      /*
       * Todo aquello precedido por `export` (declaración de variable, definición de función) queda
       * expuesto al exterior por quien requiera (`import`) este módulo.
       */
      
      export let uso_de_let_y_const = function() {
          // Declaraciones de a y b internas (o locales) en todo este bloque
          let a = 10;
          let b = {
              "x": a,
              "y": 2 * a
          };
          // Declaración de una variable, impide su re-declaración o re-asignación
          // pero no la modificación del contenido de un objeto-arreglo-referencia.
          const c = [];
      
          imprimir_variable("a", a);
          imprimir_variable("b", b);
          imprimir_variable("c", c);
      
          if (true) {
              // Ocultan las declaraciones de a y b externas a este bloque
              let a = 30;
              let b = {
                  "x": a,
                  "y": 2 * a
              };
              imprimir_variable("a", a);
              imprimir_variable("b", b);
              // La variable c es externa a este bloque
              imprimir_variable("c", c);
      
              if (true) {
                  // Ocultan las declaraciones de a, b y c externas a este bloque
                  let a = 101;
                  let b = 104;
                  const c = [100];
                  for (let i = a; i <= b; i++) {
                      // La variable i es local a este bloque
                      c.push(i);
                  }
                  c.push(105);
                  imprimir_variable("a", a);
                  imprimir_variable("b", b);
                  imprimir_variable("c", c);
              }
      
              for (let i = 1; i <= 5; i++) {
                  // La variable i es local a este bloque
                  // La variable c es externa a este bloque
                  c.push(3 * i);
              }
          }
      
          imprimir_variable("a", a);
          imprimir_variable("b", b);
          imprimir_variable("c", c);
      };
      
      export let uso_de_template_string_literal = function(sujeto) {
          let saludo = `¡Hola ${sujeto}!`;
          let palabras = ["¡", "Feliz", (new Date).getFullYear(), "!"];
          let felicitacion = `${palabras[0]}${palabras[1]} ${palabras[2]}${palabras[3]}`;
          let despedida = `
              ♜   ♞     ♝     ♛     ♚     ♝     ♞     ♜
              ¡Adios ${sujeto}!
              ♟   ♟     ♟     ♟     ♟     ♟     ♟     ♟
          `;
          imprimir_variable("saludo", saludo);
          imprimir_variable("felicitacion", felicitacion);
          imprimir_variable("despedida", despedida);
      };
      
      export let uso_de_arrow_function = function() {
          const X = 3;
      
          // Declaración de una función (x como parámetro)
          let a = ((x) => {
              let y = x <= 0 ? x * -1 : x;
              return [(y -1), y, (y + 1)];
          });
          imprimir_variable("a", a);
      
          // Aplicación de la función
          let b = a(-10);
          let c = a(10);
          imprimir_variable("b", b);
          imprimir_variable("c", c);
      
          // Declaración de una función (sin parámetro)
          let d = (() => {
              let a = [];
              for (let i = 0; i < X; i++) {
                  a.push(Math.floor(Math.random() * 100));
              }
              return a;
          });
          imprimir_variable("d", d);
      
          // Aplicación de la función
          let e = d();
          imprimir_variable("e", e);
      };
      
      export let uso_de_argumentos_opcionales = function(nombre = "N/A", apellido_paterno = "N/A", apellido_materno = "N/A") {
          // Los argumentos dados en los parámetros son opcionales. De no ser dados al momento de aplicar a la función los
          // valores que tendrán serán de "N/A" dentro de la función.
          let a = {
              "id": (Math.floor(Math.random() * 100)),
              "nombre": nombre,
              "apellidos": {
                  "paterno": apellido_paterno,
                  "materno": apellido_materno
              },
              registro: (new Date).toISOString()
          };
          imprimir_variable("a", a);
      };
      
      export let uso_de_desestructuracion = function(numero_positivo) {
          let x = numero_positivo > 0? numero_positivo : numero_positivo * -1;
          let a = [(x - 1), x, (x + 1)];
          /*
           * Declaración e inicialización de las variables b, c y d mediante la desestructuración del arreglo a
           */
          let [b,c,d] = a;
          imprimir_variable("a", a);
          imprimir_variable("b", b);
          imprimir_variable("c", c);
          imprimir_variable("d", d);
      
          let e = {
              "f": (x - 1),
              "g": x,
              "h": (x + 1)
          };
          /*
           * Declaración e inicialización de las variables f, g y h mediante la desestructuración del objeto e
           */
          let {f,g,h} = e;
          imprimir_variable("e", e);
          imprimir_variable("f", f);
          imprimir_variable("g", g);
          imprimir_variable("h", h);
      };
      
      export let uso_de_maps_y_sets = function(numero_negativo, numero_positivo) {
          let a = new Map();
          a.set("x", 10);
          a.set("y", true);
          a.set("z", "¡Hola mundo!");
          imprimir_variable("a", a);
      
          let b = new Map();
          b.set(10, numero_negativo);
          b.set(20, numero_positivo);
          b.set(30, numero_negativo);
          b.set(40, numero_positivo);
          imprimir_variable("b", b);
      
          let c = new Map([["nombre", "MUNDO"], ["apellido_paterno", "PLANETA"], ["apellido_materno", "TIERRA"]]);
          imprimir_variable("c", c);
      
          let d = new Set();
          d.add(10);
          d.add(true);
          d.add("¡Hola mundo!");
          imprimir_variable("d", d);
      
          let e = new Set();
          e.add(numero_negativo);
          e.add(numero_positivo);
          e.add(numero_negativo);
          e.add(numero_positivo);
          imprimir_variable("e", e);
      
          let f = new Set([numero_negativo, 2, 1, 0, 1, 2, numero_positivo]);
          imprimir_variable("f", f);
      
          let g = new Set([numero_negativo, numero_positivo, numero_negativo, numero_positivo, numero_negativo, numero_positivo]);
          imprimir_variable("g", g);
      };
      
      export let uso_de_clases = function() {
          let objA1 = new ClaseA();
          imprimir_variable("objA1", objA1);
          imprimir_variable("objA1.toString()", objA1.toString());
      
          let objB1 = new ClaseB();
          for (let i = 0; i < 5; i++) {
              imprimir_variable("objB1.b()", objB1.b());
          }
      
          let objC1 = new ClaseC();
          imprimir_variable("objC1.c()", objC1.c());
      };
      
      /*
       * Al no ser precedido por `export` se concidera local al módulo y solo disponible dentro del mismo.
       */
      let imprimir_variable = function(nombre, valor) {
          console.groupCollapsed(nombre);
          console.log(valor);
          console.groupEnd();
      };
      
    • js/clases/clasea.js

      export class ClaseA {
          constructor() {
              this.x = 10;
              this.y = "¡Hola mundo!";
              this.z = false;
          }
      
          toString() {
              return "ClaseA {"
                  .concat(`x: ${this.x}, `)
                  .concat(`y: ${this.y}, `)
                  .concat(`z: ${this.z} `)
                  .concat("}");
          }
      }
      
    • js/clases/claseb.js

      export class ClaseB {
          constructor(x = 7, y = 9) {
              this.i = 0;
              /*
               * Se hace uso de la clase local ClaseA, no de la encontrada en el módulo clasea.js
               */
              this.objA = new ClaseA(x, y);
          }
      
          b() {
              if (this.i === this.objA.a2()) {
                  this.i = 0;
              }
              let i = this.i;
              this.i += 1;
              return this.objA.a3(i);
          }
      }
      
      /*
       * Al no estar precedida por `export` se considera una clase local al módulo
       */
      class ClaseA {
          constructor(x, y) {
              this.i = x;
              this.j = y;
              this.as = [];
              this.a1();
          }
      
          a1() {
              for (let i = this.i; i <= this.j; i++) {
                  this.as.push(3 * i);
              }
          }
      
          a2() {
              return this.as.length;
          }
      
          a3(i) {
              return this.as[i];
          }
      }
      
    • js/clases/clasec.js

      import {ClaseB} from "./claseb.js";
      
      export class ClaseC {
          constructor() {
              this.objB = new ClaseB(2, 4);
          }
      
          c() {
              let t = 0;
              for (let i = 0; i < 6; i++) {
                  t += this.objB.b();
              }
              return t;
          }
      }
      

    Hasta este punto tendrás la siguiente estructura en $HOME/www/es602:

     alumno@servidor:~/www/es602 $ pwd && tree
     /home/alumno/www/es602
     .
     ├── index.html
     └── js
         ├── clases
         │   ├── clasea.js
         │   ├── claseb.js
         │   └── clasec.js
         ├── lib
         │   └── es6.js
         └── main.js
    
     3 directories, 6 files
    
  4. Inicia el servidor web y accede a él poniendo atención a lo impreso en Console:

    images/04.png

Observaciones:

  • Las nuevas características de ECMAScript 6 presentes son: let & const, string literals, arrow functions, optional arguments, destructuring, maps & sets y classes.
  • Las nuevas características de ECMAScript 6 no presentes son: symbols, proxies, generators y promises.
  • La gráfica de dependencia entre los módulos sería la siguiente:

    images/03.png

Lecturas