Javascript

 

ES6 / ES2015

ES6 / ES2015

Características principales de JS

  • Orientado a objetos
  • ​Basado en Prototipos
  • Funcional
  • Débilmente tipado
  • Dinámico
  • Interpretado

¿Qué es ES6?

ECMAScript v6 (abreviado como ES6 o ES2015)

es el nuevo estándar de JavaScript desde Junio de 2015.

En 1997 se crea un comité técnico (TC39) para estadarizar JavaScript por la ECMA .

Se diseña el estándar del DOM (Document Object Model) para evitar incompatibilidades entre navegadores.

A partir de entonces los estándares de JavaScript se rigen por ECMAScript

ES6 pasa a ser la mayor revisión en más de 15 años ya que actualiza y mejora funcionalidades, sintaxis y semántica que Javascript lleva arrastrando desde su versión 3.

Harmony

ES6 ó ES2015

Versionado: finalmente ES6 se acaba llamando ES2015 porque se decide sacar una versión anual. Sigue un proceso de estandarización en el que la introducción de nuevas características se divide en etapas (0-4).

Todo va avanzando sin dependencia entre las propuestas durante un año y cuando acaba ese año todo lo que esté en la etapa 4 es lo que se libera para esa versión.

-    Stage 0: borrador, primer nivel de propuesta, idea. (Strawman)
-    Stage 1: Se decide que se va a trabajar en ella (Proposal)
-    Stage 2: Especificación inicial (Draft)
-    Stages 3: Especificaciones completas e implementaciones iniciales en navegador. (Candidate)
-    Stage 4: la propuesta está lista para ser incluida en la release anual que será el nuevo estándar. (Finished)

Tabla de compatibilidades

Realmente no nos vamos a preocupar de si trabajamos con 2015, 2016 o 2017 sino si la característica que queremos utilizar es compatible con el navegador.

Esto no significa que no puedas comenzar a escribir en ES6 desde hoy mismo. Veremos cómo

Transpiladores

Como el nivel de soporte del nuevo estándar no es el mismo en todos los navegadores, y todos soportan mucho mejor ES5, han surgido unas herramientas para convertir nuestro código Javascript ES6 a ES5

Los transpiladores son programas capaces de traducir el código de un lenguaje para otro, o de una versión para otra. 

No compilan, solo traducen.

translator + compiler

Principales Novedades ES6

  • Let / Const
  • Arrow Function
  • Parámetros por defecto
  • Parámetros Rest
  • Spread Operator
  • Destructuring
  • Template Strings
  • Promesas
  • Clases y Herencia
  • Módulos

let / const    vs.     var

ES5 -> La única forma de declarar variables era con la palabra reservada 'var'.

Las variables declaradas así podían ser de ámbito (scope):

Había un caso especial. Si declarábamos una variable sin 'var' ni nada que la precediera dentro de una función, esta variable pasaba a tener ámbito global.

  • Global: declaradas fuera de cualquier función
  • Local: declaradas dentro de una función y sólo accesibles dentro de ella
(function-level scope)

ES5

    
    function miFuncion() {
      console.log(miVar);            // miVar es undefined (está declarada, pero no tiene valor asignado)
      if (true) {
        var miVar = "Hola mundo";
      }
      console.log(miVar);            // miVar es 'Hola mundo' (está declarada y tiene valor)
    };

var

ES5

(function-level scope)

En ES5 cuando definíamos una variable en el interior (scope) de una función, el intérprete interno pasaba a declararla al comienzo de su contexto de ejecución (la eleva);

hoisting


    var x = 5;
 
    (function () {
        console.log("x:", x); //se espera 5
        var x = 10;
        console.log("x:", x); //se espera 10
    }());

   var x = 5;
 
    (function () {
        var x; // <- la variable es elevada
        console.log("x:", x); //-> undefined
        x = 10;
        console.log("x:", x); //-> 10
    }());

ES5

Cuando creamos una función utilizando la sintaxis function declaration, la declaración y la definición de la función son elevadas, sin embargo cuando utilizamos la sintaxis para function expression, sólo se eleva la variable, pero no su valor.


    console.log("fn1", fn1()); //que imprime?
    console.log("fn2", fn2()); //que imprime?
     
    //function expression
    var fn1 = function() { return 1; };
     
    //function declaration
    function fn2() { return 2; }

    var fn1; // <- la variable es elevada
    function fn2() { return 2; } // <- declaración 
                                 // y definición son elevadas
     
    console.log("fn1", fn1()); //throw TypeError: 
                               // undefined is not a function
    console.log("fn2", fn2()); //2
     
    //function expression
    fn1 = function() { return 1; };

ES5

hoisting

Con ES6 aparece una nueva forma de declarar variables, utilizando la palabra reservada let, siendo su scope a nivel de bloque (todo lo que queda entre dos llaves {})

(block-level scope)

let / const


    for (const i of [0, 1, 2...]) {    
        console.log(i);
    }
    // en un for...of se crea un bucle para iterar a través de los elementos de objetos iterables
    // (Array, Map, Set, el objeto arguments,...) podríamos declarar la variable iteradora con 'const'
    // porque a cada vuelta, se está creando un nuevo scope y distintas constantes 'i'

También es novedad poder crear constantes, usando const, que son solo read-only e inmutables a lo largo del programa. Y como con let, también tienen scope a nivel de bloque.  Las constantes además deben inicializarse.

TIP: Nuestro código debería tener más declaraciones 'const' que 'let'

ES6

Usa let si puedes necesitar reasignarle un valor a la variable. Y const  cuando estés segura de que no. 

(block-level scope)

let / const: consejos

Intenta declarar siempre tus variables antes de necesitar usarlas, en ES6 no hay hoisting y si no la tienes declarada antes de su uso obtendrás un 'Reference Error'.

 

Si necesitas tener hoisting en una función, recuerda que solo se mantiene para las declaradas en forma de declaración, no para las expresiones (funciones anónimas) ni para las arrow functions que veremos a continuación. 

ES6


    // Declaration:                    // Expression:                    // Expression with arrow:
    function foo() {}                const foo = function () {};            let foo = () => {};
                                

arrow function ()=>

Funciones anónimas escritas de una forma más compacta que además no generan su propio this. Por lo que estaremos haciendo referencia al bloque en el que está definida.

    
    var sum = function (a,b){
        return a + b;
    }
    
    let sum = (a, b) => a + b;

TIP: Si solo le pasamos 1 parámetro a la función no se necesitan los paréntesis.

Si no pasamos parámetros, se ponen los paréntesis vacíos ().
Si tenemos que ejecutar más de una sentencia, las pondremos entre llaves y usaremos la palabra reservada 'return' para el retorno de la función

ES6

lambdas

arrow function ()=>

  • Son siempre anónimas. Estamos utilizando una estructura declarativa donde asignamos la función a una variable lo que nos permite su reutilización.
  • No pueden ser utilizadas como constructores. No se puede usar el new.
  • La sintaxis es mucho más limpia y simple.
  • El objeto arguments no funciona.
  • Para devolver un objeto de forma literal, la sintaxis de las funciones flecha exige el uso de paréntesis alrededor de las llaves.

 

  • Al igual que ocurre las funciones tradicionales autoejecutables –-IIFE-, las funciones flecha también permiten su ejecución inmediata –IIAF– (Immediately-invoked arrow functions).

ES6

lambdas
    let getAda = () => ({name: 'Adajs'});
(() => {
  console.log('Ok');
})()
(function(){
   console.log('Ok')
})();

IIFE

iiaf

algo más sobre el this

El this en Javascript se comporta de modo diferente a otros lenguajes. 

En Javascript todo son objetos, incluidas las funciones y métodos. 

Cada función define su propio valor del this (un nuevo objeto en el caso de un constructor, undefined en llamadas a funciones en modo estricto, el objeto contextual si la función se llama como un "método de un objeto", etc).

ES5/6

  • En el contexto de ejecución global (fuera de cualquier función), this se refiere al objeto global, ya sea en modo estricto o no.

 

  • Dentro de una función, contexto local, el valor de this depende de cómo la función es llamada.

En general, evalor de this está determinado por cómo se llama a la función.

Su valor, lejos de ser intuitivo, se asocia a cada uno de los ámbitos/scopes desde el que se invoca la función.

algo más sobre el this

ES5/6


    function Persona() { 
       // El constructor Persona() define `this` como una instancia de sí mismo.   
       this.edad = 0; 
       setInterval(function crecer() { 
          // En modo no estricto, la función crecer() define `this` 
          // como el objeto global, el cual es diferente al objeto `this` 
          // definido por el constructor Persona().
          this.edad++; 
       }, 1000); 
    } 
    
    var p = new Persona();

_this_ dentro de un handler apunta al elemento que ha provocado el evento

_this_ dentro de un método de un objeto apunta al objeto

 

en ES6, con las arrows functions, el this siempre apunta al objeto padre. Si queremos apuntar al elemento que ha provocado el evento lo podemos hacer con event.target

 

WHAT????

Con las arrow functions,    () => 

la asociación entre el contexto y el valor del this, se produce de forma nativa,

por lo que el código funciona como se espera.

 

this

Parámetros por defecto

Permiten que los parámetros de la función sean inicializados con valores por defecto, por si no se le pasan valores o los valores pasados son undefined.
En JavaScript, los parámetros de funciones son por defecto undefined. En algunas situaciones puede ser útil colocar un valor por defecto diferente.


    function setBackgroundColor(element, color = 'pink') {
      element.style.backgroundColor = color;
    }
    
    setBackgroundColor(myDiv);                // color configurado a 'pink'
    setBackgroundColor(myDiv2, undefined);    // color también configurado a 'pink'
    setBackgroundColor(miSpan, 'blue');       // color configurado a 'blue'

ES6

Parámetros por defecto

TIP: A tener en cuenta que si invocamos al objeto arguments de la función nos retornará el número exacto de parámetros pasados, no los default.


    var myFunc = function ( x = 10, y = 20, z = 30 ) {
        var sum = x + y + z;
 
        return sum + ' (' + arguments.length + ' arguments passed)';
    };
    
    console.info( myFunc( 1, 2, 3 ) ); // 6 (3 arguments passed)
    console.info( myFunc( 1, 2, undefined ) ); // 33 (3 arguments passed)
    console.info( myFunc( 1, undefined ) ); // 51 (2 arguments passed)

ES6

Parámetros Rest

Una de las nuevas funcionalidades es poder agrupar los argumentos que llegan a nuestra función en un array.

Es muy útil para cuando no sabemos exactamente cuántos parámetros le vamos a pasar a nuestras funciones por ejemplo.
Está estrechamente relacionado con el objeto arguments, aunque presenta algunas diferencias.
La forma de implementarse recuerda a Ruby

ES6


    function ( , ...)

Parámetros Rest

Esta función, con sus peculiares tres puntos delante del tercer argumento, estarían indicándole al intérprete que ese valor debe ser un array compuesto por los parámetros que lleguen desde la llamada siguiendo la siguiente lógica:

  • El primer parámetro que llegue, se mapea como foo, el segundo como bar.
  • El resto, sea cual sea el número, se guardarán dentro de un array definido como theArgs.

ES6


    let myFunc = function ( foo, bar, ...theArgs ) {

        console.info( 'foo: ', foo );
        console.info( 'bar: ', bar );
        console.info( 'theArgs: ', theArgs );
    }

    myFunc( 'myParam1', 'myParam2', 'myParam3', 'myParam4', 'myParam5' );
        
    // Retorna:
    // foo: myParam1
    // bar: myParam2
    // theArgs: ["myParam3", "myParam4", "myParam5"]

Parámetros Rest

  • Una vez que utilizamos esta funcionalidad, dejamos de tener acceso al objeto arguments

 

  • Otra característica importante es que estos rest arguments si constituyen un verdadero array, a diferencia de arguments, que dan lugar a un objeto similar a un array, que tiene algunas de sus propiedades como length pero que carece de otras como shift o pop

 

  •  No podemos asignar un valor por defecto a este tipo de objeto, ya que en caso de omisión, el intérprete ya asigna un array vacío

ES6

Destructuring

Expresión que nos permite descomponer un array u objeto

para asignarlo a un conjunto de variables. 

Si vamos a descomponer las propiedades de un objeto, es importante que las variables a las que van a parar tengan el mismo nombre que las propiedades que queremos asignar.

ES6

    
    let foo = ["uno", "dos", "tres"];
    
    // sin destructuring
    let uno  = foo[0];
    let dos  = foo[1];
    let tres = foo[2]; // asignación en tres lineas
    
    // con destructuring
    let [uno, dos, tres] = foo; // asignación en una sola linea    

Destructuring

Gracias a destructuring assignment, las funciones pueden retornar multiples valores. Aunque en JavaScript siempre ha sido posible regresar un arreglo de una función, esto agrega más flexibilidad.

ES6

    
    function f() {
      return [1, 2];
    }

    let a, b;
    [a, b] = f();
    console.log("A es " + a + " ,B es " + b);

    // A es 1, B es 2

swap

Qué creéis que está pasando aquí?

ES6

    
    var a = 1;
    var b = 3;
    
    [a, b] = [b, a];

Estamos cambiando el orden de las variables. Después de ejecutarlo

b será igual a 1 y a igual a 3.

Sin destructuring assignment, cambiar el orden de dos variables

requiere una variable temporal

Spread Operator

Nos  permite pasar un array de elementos a una función, convirtiendo cada uno de los elementos en un argumento.

Se podría pensar en que es la versión inversa de los parámetros rest. 

Lo podemos usar junto con el new para instanciar.

ES6


    function f(x, y, z) { }
    let args = [0, 1, 2];
    f(...args);        //f(0, 1, 2);
    
    let parts1 = ['shoulder', 'knees'];
    let parts2 = ['chest', 'waist'];
    let lyrics = ['head', ...parts1, ...parts2, 'and', 'toes'];
    //lyrics = ['head', 'shoulder', 'knees', 'chest', 'waist', 'and', 'toes']

Template Strings

Con ellas, tenemos una nueva forma de escribir strings en JavaScript.
Es bastante cómoda y legible.
Nos permite tener cadenas multilínea, sin tener que usar '\n'  e interpolar variables evitando que tengamos que concatenarlas usando el '+'.
Nos pueden servir para construir templates (plantillas html dinámicas).  

Se le indican al intérprete de Javascript usando los acentos

graves `` (backticks).

Para meter valores de variables o resultados de fs. puedes usar ${var/función}

ES6

ejemplos de Template Strings

ES6

    
    let nombre = 'Adas';
    let mensaje = `1. Ésta es una línea normal
    2. Hola ${nombre}!`;

    console.log(mensaje);

    // 1. Esta es una línea normal
    // 2. Hola Adas!
    
    let getNombres = () => 'Pepa y Pepe';
    
    let texto = `Los nombres son: ${getNombres()}
    La suma de 5 + 7 da ${5+7}`;
    
    console.log(texto);

    // Los nombres son: Pepa y Pepe
    // La suma de 5 + 7 da 12
  
    const data = {  
       nombre: "Google Pixel L",
       imagen: "http://example.com/miImagen.png",
       precio: 699,
    };
    
    const miProducto = `<article>  
      <h1>${data.nombre}</h1>
      <img src="${data.imagen}" />
      <span>${data.precio} €</span>
    </article>`;
    
    console.log(miProducto);  

    /* "<article>
      <h1>Google Pixel L</h1>
      <img src=http://example.com/miImagen.png />
      <span>699 € </span>
    </article>"  
    */

Fácil, no?

Promesas

ES6

Promesas

Las promesas nos permiten manejar operaciones asíncronas de forma síncrona

 

Una promesa representa el resultado a una operación que estará disponible en algún momento en el futuro

 

 

 

Las promesas se utilizan en JavaScript desde hace años gracias a librerías como Q, Bluebird, RSVP, o incluso jQuery

ES6

Promesas

Al crear una promesa, el constructor nos proporciona dos handlers o funciones callback como parámetros

  • Resolve: la función que ejecutaremos con el resultado de la operación asíncrona, si ésta es satisfactoria
  • Reject: la función que ejecutaremos en caso de que la operación asíncrona falle

    new Promise((resolve, reject) => {
        if (/* operación satisfactoria */) {
            resolve(/* resultado */);
        } else { // operación fallida
            reject(/* razón */);
        }
    })
    

ES6

Promesas

 

Una promesa tendrá en todo momento uno de estos 3 estados:

  • pending - Pendiente
  • fulfilled - Resuelta
  • rejected - Rechazada

 

El resultado de una promesa es inmutable.

La promesa garantiza que siempre obtendremos su resultado, independientemente de cuando lo consultemos (tanto si está pendiente como si ya se resolvió)

ES6

Consumir promesas

Para obtener el resultado de una promesa deberemos registrarle handlers mediante los métodos then y catch, que son encadenables.

 

El método then acepta dos parámetros:

  • El primero es la función que se ejecutará cuando la promesa se resuelva
  • El segundo es la función que se ejecutará cuando la promesa se rechace

 

El método catch tan sólo acepta un parámetro, que es la función que se ejecutará cuando la promesa se rechace

ES6

Consumir promesas


    function sumaConEspera (a, b) {
        return new Promise((resolve, reject) => {            
            if (a === null || b === null) {
                return reject('Booooh!');
            }
            setTimeout(() => {
                resolve(a + b);
            }, 500)
        })
    }

    sumaConEspera(4, 5)
        .then(console.log) // la consola mostrará '9' tras 0.5 segundos
        .catch(console.log) // nunca se ejecutará

    sumaConEspera(null, 5)
        .then(console.log) // nunca se ejecutará
        .catch(console.log) // la consola mostrará 'Booooh!'

ES6

Consumir promesas


    const p = new Promise((resolve, reject) => {
        const random = Math.round(Math.random() * 10)
        if (random >= 5) resolve(random)
        else reject('suspendido!')
    }

    p.then(resultado => console.log(resultado),
           error => console.log(error));

    p.then(resultado => console.log(resultado))
     .catch(error => console.log(error))

    [...]

    p.then(null,
           error => console.log(error));

    p.catch(error => console.log(error));

ES6

Operaciones asíncronas con promesas


    function httpRequest (url) {
        const headers = new Headers();
        headers.append('Content-Type', 'application/json');

        return new Promise((resolve, reject) => {
            fetch(url, {
                method: 'GET',
                headers
            })
            .then(response => {
                resolve(response.json())
            })
            .catch(reject)
        })
    }

    httpRequest('https://jsonplaceholder.typicode.com/users/1')
        .then(data => console.log(data.name)) // la consola mostrará 'Leanne Graham'
        .catch(console.error)
        

ES6

Promise.all()

Cuando necesitamos trabajar con los resultados de diversas operaciones asíncronas, tenemos que esperar a que todas ellas se hayan procesado para proseguir.

 

Promise.all() recibe un array de promesas, devolviendo a su vez una nueva promesa que se resolverá cuando todas las anteriores se hayan resuelto; si una sola de las promesas es rechazada, también lo será Promise.all()

ES6

Promise.all()


    const urls = [
        'https://jsonplaceholder.typicode.com/users/1',
        'https://jsonplaceholder.typicode.com/users/2',
        'https://jsonplaceholder.typicode.com/users/3'
    ]

    const promesas = urls.map(httpRequest) // el método que hemos definido anteriormente

    const promesaDefinitiva = Promise.all(promesas)

    promesaDefinitiva
        .then(resultados => {
            resultados.forEach(res => console.log(res.name))
            /* la consola mostrará
               Leanne Graham
               Ervin Howell
               Clementine Bauch
            */
        })
        .catch(console.error)
        

ES6

Clases

Las clases de JavaScript són, en esencia, azúcar sintáctico sobre la ya existente herencia basada en prototipos.

 

Con la palabra reservada class ES6 introduce una forma mucho más sencilla y una sintaxis más clara para definir objetos y trabajar con herencia.

ES6

    
    class Rectangulo {
        constructor(alto, ancho) {
            this.alto = alto;
            this.ancho = ancho;
          }
  
        calcArea () {
            return this.alto * this.ancho;
        }
    }
    
    function Rectangulo (alto, ancho) {        
        this.alto = alto;
        this.ancho = ancho;
    }
  
    Rectangle.prototype.calcArea = function () {
        return this.alto * this.ancho;
    }

Constructor

La clase puede tener un método constructor, que se ejecuta para crear e inicializar una instancia de la misma.

 

Utilizamos la palabra reservada new para crear instancias de una clase.

ES6

    
    class Rectangulo {
        constructor(alto, ancho) {
            this.alto = alto;
            this.ancho = ancho;
          }        
    }

    const p = new Rectangulo(4, 5);
    console.log(p.alto);   // la consola mostrará '4'
    console.log(p.ancho);  // la consola mostrará '5'

Definición de métodos

Los métodos son las funciones que expone la clase a todas sus instancias.

ES6

    
    class Rectangulo {
        constructor(alto, ancho) {
            this.alto = alto;
            this.ancho = ancho;
          }
  
        calcArea () {
            return this.alto * this.ancho;
        }
    }

    const r = new Rectangulo(4, 5);
    console.log(r.calcArea()); // la consola mostrará '20'

Definición de métodos

La nueva sintaxis de clase de ES6 no permite definir métodos ni variables privados, a diferencia de la sintaxis clásica, que se aprovecha de las clausuras para conseguirlo.

ES6

    
   var Rectangulo = (function () {
        function Rectangulo (alto, ancho) {
            var perimetro = alto*2 + ancho*2;
            this.alto = alto;
            this.ancho = ancho;
                    
            function area () {
              return this.alto * this.ancho;
            }
            
            this.calcArea = area;

            this.calcPerimetro = function () {
              return perimetro;
            }
        }

        return Rectangulo;
    } ())
   
    var r = new Rectangulo(4, 5);
    console.log(r.calcArea());        // la consola mostrará '20'
    console.log(r.calcPerimetro());   // la consola mostrará '18'

getters y setters

Los métodos get y set nos permiten usar la notación estándar de acceso a propiedades para lectura y escritura (como llamar a una función sin tener que usar los paréntesis), permitiendo a la vez personalizar la forma en que la propiedad es recuperada y mutada.

ES6

    
    class Cuadraro {
        constructor(lado) {
            this.lado;
        }
  
        get area () {
            return this.lado * this.lado;
        }
    }

    const r = new Cuadrado(5);
    console.log(r.area);  // la consola mostrará '25'
    
    class Cuadrado {
        constructor(lado) {
            this.lado = lado;
        }
  
        set area (a) {
            return this.lado = Math.sqrt(a);
        }
    }

    const c = new Cuadrado(5);
    console.log(c.lado);  // la consola mostrará '5'
    c.area = 9;
    console.log(c.lado);  // la consola mostrará '3'

GET

SET

Métodos estáticos

La palabra reservada static sirve para definir métodos estáticos en una clase.

Los métodos estáticos se llaman sobre su clase sin necesidad de instanciarla, y por lo tanto no pueden acceder a las propiedades ni métodos de la misma. Del mismo modo una instancia de una clase no puede acceder a sus métodos estáticos.

ES6

    
    class Rectangulo {
        constructor(alto, ancho) {
            this.alto = alto;
            this.ancho = ancho;
        }
  
        static area (alto, ancho) {
            return alto *  ancho;
        }
    }

    console.log(Rectangulo.area(4, 5));  // la consola mostrará '20'
    const r = new Rectangulo(4, 5);
    console.log(r.area());               // ERROR!

Los métodos estáticos se suelen utilizar para crear "funciones de utilidad" en aplicaciones

Herencia

ES6

    
    class Animal {
        constructor (nombre) {
            this.nombre = nombre;
        }

        hablar () {
            console.log(`${this.nombre} hace ruido`);
        }
    }

    class Perro extends Animal {
        hablar () {
            console.log(`${this.nombre} ladra`);
        }
    }

    var p = new Perro('Pocho');
    p.hablar(); // 'Pocho ladra'

La palabra reservada extends se utiliza en la definición de clases para crear una clase como "hija" de otra clase. Por eso decimos que la clase hija "hereda" los métodos y propiedades de su clase padre.

 

La clase hija puede extender a su clase padre añadiendo nuevas propiedades y métodos, así como sobreescribir los métodos originales de su clase padre.

Super

ES6

    
    class Animal {
        constructor (nombre) {
            this.nombre = nombre;
        }

        hablar () {
            console.log(`${this.nombre} hace ruido`);
        }
    }

    class Leon extends Animal {
        constructor (nombre) {
            super(nombre);
            this.colmillos = 4;
        }

        hablar () {
            super.hablar();
            console.log(`${this.nombre} ruge`);
        }
    }

    var p = new Leon('Simba');
    p.hablar();
    // 'Simba hace ruido'
    // 'Simba ruge'

Toda instancia de una clase hija puede acceder y llamar a los métodos de su clase padre mediante la palabra reservada super.

 

Además, si una clase hija define su propio constructor, debe obligatoriamente llamar en el mismo al método constructor de su clase padre, también mediante super.

ejemplos de herencia

ES6

    
    class Persona {
        constructor (nombre, fuerza = false) {
            this.nombre = nombre;
            this.sienteFuerza= fuerza;
        }
        
        caminar () {
            console.log(`${this.nombre} camina`)
        }
        correr () {
            console.log(`${this.nombre} corre`)
        }
    }

    class Jedi extends Persona {
        constructor (nombre, status = 'Padawan') {
            super(nombre, true);
            this.status = status;
        }

        trucoMental () {
            console.log(`${this.nombre} realiza truco mental`)
        }
        superSalto () {
            console.log(`${this.nombre} realiza super salto`)
        }
    }
    
    const Finn = new Persona('Finn');
    const Leia = new Persona('Leia', true);
    const Luke = new Jedi('Luke', 'Maestro');
    const Rey = new Jedi('Rey');

    console.log(Leia.sienteFuerza);  // 'true'  
    console.log(Luke.status);        // 'Maestro'
    console.log(Rey.sienteFuerza);   // 'true'
    console.log(Rey.status);         // 'Padawan'
    console.log(Finn.status);        // 'undefined'

    Finn.caminar();       // 'Finn camina'
    Luke.correr();        // 'Luke corre'
    Rey.trucoMental();    // 'Rey realiza truco mental'
    Leia.superSalto();    // ERROR!

Módulos

Un módulo es una unidad de código auto contenido en un fichero.

Puede exponer una interfaz pública mediante export.

Puede utilizar código expuesto por otro módulo mediante import.

    
    // fichero 'operaciones.js'

    export function sumar (a, b) {    
        return a + b;
    }

    export function restar (a, b) {
        return a - b;
    }
    
    // fichero 'calculadora.js'

    import { sumar } from './operaciones';

    function calcular (a, b, op) {
        switch (op) {
        case 'SUMAR':
            return sumar(a, b);
            [...]
        }
        [...]
    }

ES6

¿Por qué usar módulos?

  • Mantenibilidad: realizar un cambio en el código es más rápido y sencillo si éste está bien desacoplado

 

  • Reusabilidad: no necesito volver a escribir una función si puedo importarla

 

  • Limpieza: al importar módulos evito contaminar el scope de mi aplicación con variables globales

ES6

Módulos en JavaScript

AMD

 

  • Sintaxis complicada

  • La implementación más popular de este estándar es RequireJS

  • Diseñado para carga asíncrona

  • Utilizado principalmente en navegadores web (frontend)

CommonJS

 

  • Sintaxis compacta
  • La implementación más popular de este estándar es NodeJS
  • Diseñado para carga síncrona
  • Utilizado principalmente en servidores (backend)
(Asynchronous Module Definition)

ES5

Módulos en ES6

La sintaxis de los módulos en ES6 permite dos tipos de exportaciones

  • Por nombre
  • Por defecto (default)

    // fichero 'circulo.js'    

    export const pi = 3.14159265;

    export function area (radio) {
        return pi * radio * radio;
    }

    // fichero 'main.js'

    import { pi, area } from './circulo'

    // fichero 'cuadrado.js'    

    export default function area (lado) {
        return lado * lado;
    }

    // fichero 'main.js'

    import area from './cuadrado'

ES6

Módulos en ES6

Puedo importar todas las funciones de un módulo y accederlas como propiedades de un objeto


    // fichero 'circulo.js'    

    export const pi = 3.14159265;

    export function area (radio) {
        return pi * radio * radio;
    }

    export function diametro (radio) {
        return radio * 2;
    }

    // fichero 'main.js'    

    import * as circ from './circulo'

    function calcular (radio) {
        const area = circ.area(radio);
        const diametro = circ.diametro(radio);

        console.log(`Área: ${area}`);
        console.log(`Diámetro: ${diametro}`);
    }

ES6

Algunos ejemplos más...


    // fichero 'foo.js'

    export const func1 = () => {
        console.log('soy func1')
    }

    export { func1 as default }

    export const func2 = () => {
        console.log('soy func2')
    }

    const func3 = () => {
        console.log('soy func3')
    }

    export { func3 as foo }

    // fichero 'bar.js'

    import func1, { func2 } from './foo';

    [...]

    import { func1, func2, foo } from './foo';

    [...]

    import { foo as func3 } from './foo';

    [...]

    import * as foo from './foo';
    foo.func1(); // 'soy func1'
    foo.func2(); // 'soy func2'
    foo.func3(); // ERROR!
    foo.foo();   // 'soy func3' 
    

ES6

Y éste, a grandes rasgos, es nuestro paseo por las novedades de

ES6

GRACIAS!!!

Ahora ya podéis volar solas

JavaScript ES6 / ES2015

By adaJS

JavaScript ES6 / ES2015

by AdaJS team

  • 2,231