ECMAScript 6: el futuro de JavaScript

¿Qué es ECMAScript 6?

ECMAScript 6 es la nueva versión del lenguaje estandar ECMAScript que esta terminada desde Junio de 2015. ES6 es la primer actualización al lenguaje desde que en 2008 salio ECMAScript 5.

Usando ECMAScript 6 hoy

Babel.js

Babel.js logo

Babel.js es un transpiler que permite convertír código de ECMAScript 6 a código compatible con la mayoría de navegadores modernos.

Instalando Babel.js

Para poder usarlo lo primero es instalarlo, para esto necesitamos tener Node.js o io.js instalado en nuestra computadora.

Una vez instalado node (desde acá voy a usar node para referirme a io.js y Node.js) usando NPM instalamos Babel.js de forma global con el comando

sudo npm i -g babel

Luego cuando queramos usar Babel podemos usamos el siguiente comando.

babel archivo.js -o build.js

Este nos va a convertir el código de archivo.js de ES6 a ES5 y mostrar el resultado en la consola.

babel-node archivo.js

Este nos va a convertir el código de archivo.js y ejecutarlo con node, de esta forma podemos usar todas las características de ES6 en node.

Usandolo con Browserify

Babel se puede utilizar con Browserify gracias a un plugin de este llamado Babelify, para esto simplemente instalan Browserify y Babel como dependencia de desarrollo de su proyecto con el siguiente comando.

[sudo] npm i -D browserify babelify

Luego utilizamos Browserify pasandole Babelify como transform con el comando:

browserify -t babelify -i src/main.jsx -o build/main.js

Esto va a convertír nuestro código ES6 a ES5, generar un único archivo a partír de nuestro main.js ubicado en la carpeta src, cargar los módulos que hayamos requerido desde node_modules y crear un único archivo ES5 en la carpeta build.

Usandolo con Gulp

Babel también se puede utilizar con Gulp.js utilizando el plugin gulp-babel, para esto descargan Gulp.js y gulp-babel con el siguiente comando.

[sudo] npm i -D gulp gulp-babel

Luego creamos una tarea de Gulp en nuestro archivo gulpfile.js en la raíz del proyecto en la cual leemos los archivos en ES6, ejecutamos gulp-babel y luego guardamos los archivos generados en otra carpeta.

var gulp  = require('gulp');
var babel = require('gulp-babel');

gulp.task('js', function () {
  gulp.src('/src/es6/*.js')
    .pipe(babel())
    .pipe(gulp.dest('/build/js/'));
});

Usandolo con Nodemon

Babel también se puede utilizar con nodemon simplemente agregando algunos parámetros al momento de ejecutar nodemon usando el siguiente comando:

nodemon --exec babel-node -- server.js

Con esto podemos usar babel-node para correr nuestra aplicación con Node.js y que cada vez que se realice un cambio se reinicie el servidor.

Usandolo con Mocha

Babel también se puede utilizar con Mocha simplemente agregando algunos parámetros al momento de ejecutar Mocha usando el comando:

mocha --compilers js:babel/register

Variables de bloque y constantes

Variables de bloque

En ES6 se agrega una nueva forma de definir variables usando la palabra let en vez de var.

Se diferencia de var en que el scope de una variable definida con let es el bloque en el cual se encuentra la variable y no la función.

Ejemplo:

Constantes

Algo que sin duda faltaba en JS era las constantes. Con ES6 es posible definir tus propias constantes usando la palabra const en lugar de let o var.

Una constantes como el nombre indica no puede cambiar de valor una vez definida, tiene un valor constante.

Las constantes también tienen un scope de bloque.

Template strings

Los template string son una forma más fácil de crear strings con variables en medio del string o strings multilínea.

Variables en strings

Para meter una variable dentro de un template string hay que colocar el nombre de esta variable entre de ${ y } (no solo variables, incluso pueden ejecutar funciones o colocar expresiones como 2+2).

Strings multilínea

Para poder crear un string multilínea con template strings basta con apretar enter y en la siguiente línea seguír escribiendo.

Números en Octal y Binario

Números en Octal

Desde ES6 va a ser posible definir variables usando números en Octal con el siguiente código

Números en Binario

Desde ES6 va a ser posible definir variables usando números en Binario con el siguiente código

Objeto Math

Métodos de Arrays

Array.from(array, mapFn)

Este nuevo método del objeto Array permite crear un array copiando otro array o un NodeList.

Es posible utilizarlos actualmente mediantes polyfills.

Otros métodos

Además de .from() se agregaron los siguientes métodos:

  • .of(): crea un nuevo array con un número variado de elementos
  • .fill(): llena un array con un nuevo valor en cada elemento
  • .find(): busca un elemento dentro de un array y devuelve el valor
  • .findIndex(): similar a .find() pero devuelve el índice
  • .entries(): devuelve una instancia del objeto Iterator que contiene cada índice y valor del array
  • .keys(): similar a .entries() pero el Iterator solo muestra los índices
  • .copyWithin(): copia los elementos de un array en las posiciones indicadas

Métodos de Object

Object.assign(objetivo, ...objs)

Este nuevo método permite asignar propiedades de uno o más objetos a otro objeto pisando las propiedades con nombres repetidos por el valor del último objeto indicado.

Esta propiedad es muy útil para realizar herencia entre objetos.

Este método se puede utilizar ya gracias a un polyfill

Object.is(valor1, valor2)

Este nuevo método sirve para comparar si dos valores son iguales, devuelve true si ambos son:

  • undefined
  • null
  • true o false
  • strings con el mismo largo y los mismos caracteres
  • el mismo objeto
  • números y ambos:
    • son mayores a 0
    • son menores a 0
    • son NaN
    • no son 0, no son NaN y son el mismo número

Al igual que .assign() se puede utilizar ya mismo mediante un polyfill.

Forma abreviada de definición de Objetos

Asignación de propiedades

Con ES6 ahora va a ser mucho más simple (y lógico) utilizar una variable para definir el valor de una propiedad de un objeto.

Asignación de métodos

Al igual que es más fácil usar variables en propiedades también se simplificó la forma de definir métodos en un objeto.

Asignación por descomposición

Si ya dijimos que con ES6 nos es más fácil crear objetos usando variables, también nos vas a ser más fácil hacer lo contrarios, descomponer un objeto (o un array) en variables

Parámetros por defecto

Algo que siempre falto en JS al momento de definir funciones eran los parámetros con valores por defecto, siendo la única forma de lograr esto redefinir el valor de un parámetro con el mismo parámetro o el valor por defecto (no muy optimo que digamos).

Con ES6 ahora es completamente posible definir un valor por defecto a los parámetros de nuestras funciones al igual que en otros lenguajes de programación.

Arrow functions

Arrow function es una nueva forma de definir funciones en JS similar a como hace CoffeeScript.

Hay distintas variantes en la sintaxis de las arrow function.

Función de un solo parámetro

Al crear una arrow function de un solo parámetro no es necesario escribír los paréntesis.

Como se puede ver en el ejemplo tampoco es necesario escribír las llaves siempre. Esto ocurre solo cuando la función es de una sola línea y devuelve un valor.

Función de varios parámetros

En el caso de que queramos utilizar más de un parámetro ahí sí es necesario envolver el nombre de estos entre paréntesis.

Función sin parámetros

También son necesarios los paréntesis si queremos crear una función que no reciba parámetros.

Función con cuerpo

Por último, si la función tiene más de una línea (o no devuelve ningún valor) es necesario utilizar las llaves.

Parámetros rest

Los parámetros rest son una forma de utilizar parámetros virtualmente infinitos (nunca supe de ningún límite) en una función que vendría a substituír al array arguments que tienen actualmente las funciones.

Los parámetros rest se definen agregando ... adelante del nombre que se le quiera asignar al mismo. El parámetro rest tiene que ser siempre el último parámetro de una función.

Promesas

Las promesas es algo que se viene usando ya desde hace un par de años gracias a librerías como Q.

En ES6 las promesas van a pasar a tener soporte nativo del lenguaje con una sintaxis bastante simple.

Generadores

Los generadores son un tipo de función especial que permite parar la ejecución de la misma y devolver un valor, para luego poder seguír ejecutándola.

Ejecutar

Iterators y for...of

Iterators

Los Iterators son un tipo de objeto que nos permite iterarlos usando el método .next() (los generadores son instancias de Iterator).

for...of

Este es un nuevo bucle similar a for...in donde la variable que usamos para recorrer un array devuelve el valor de cada elemento y no la posición.

Este bucle sirve perfectamente para recorrer un Iterator.

Proxies

Los proxies de ES6 te permiten interceptar y personalizar las distintas operaciones que se pueden realizar en un objeto.

Clases

Desde ES6 se incorporan al lenguaje clases para poder hacer POO más facilmente (sin prototype). Las clases de ES6 son solo un syntax sugar de la como se hace actualmente con prototype.

Definición de clase

Para definir una clase simplemente se usa la palabra class seguida del nombre de la clase y luego entre llaves los métodos de esta.

Extendiendo una clase

Al igual que en otros lenguajes es posible extender una clase agregando extends ClaseBase luego del nombre de la nueva clase.

Métodos estáticos

También es posible definir métodos estáticos que se pueden ejecutar sin necesidad de instanciar la clase simplemente agregando static antes del nombre del método (el método constructor no puede ser estático).

Getters y Setters

Por último también es posible definir getter y setters agregando get o set antes del nombre de un método.

Módulos

Desde ES6 vamos a tener un sistema nativo de módulos que viene a sustituir a los actuales CommonJS, AMD, etc.

Hay varias formas de exportar e importar módulos con el nuevo sistema.

Exportación única

La primera forma es cuando tenemos un solo dato a exportar (una función, un objeto, etc.), para esto usamos la siguiente sintaxis.

Multiples exportaciones

Se puede dar el caso de querer exportar muchos datos al mismo tiempo, para eso simplemente quitamos el default luego del export.

Combinandolos

Por último puede pasar que quieras dejar una exportación por defecto y la posibilidad de importar otros datos especificando.

Importando de forma síncrona

Para importar hay dos forma, la primera es la forma síncrona, esta a su vez tiene varias forma. pero todas se basan es usa import seguido del nombre que se le quiere dar al módulo a importar y luego from y la ubicación del módulo en un string.

Importando de forma asíncrona

La otra forma es la importación asíncrona de módulos, esta además tiene la característica de que va a funcionar desde etiquetas <script> en el HTML.

La forma asíncrona tiene dos variantes, una que es la más simple, para cargar un solo módulo, la otra que requiere el uso de promesas permite cargar múltiples módulos de forma asíncrona.

Symbols

Introducción

Los Symbol son un nuevo tipo de primitivo inmutable pensado para ser usado principalmente como identificador de las propiedades de un objeto.

Creando y usando un Symbol

Con la incorporación de los Symbol las propiedades de un objeto ahora se podrán acceder tanto con comillas como sin comillas.

Symbol.for()

El objeto Symbol (usado para crear un nuevo primitivo Symbol) posee un método llamado .for(). Este método tiene dos usos, el primero es la creación de un nuevo Symbol, sin necesidad de asignar a una variable, el segundo es encontrar un Symbol ya creado.

Usandolos para propiedades privadas

Un posible uso de los Symbol es para poder crear propiedades semi-privadas en object literals.

Colecciones de datos

Map

Los Map son un tipo de estructura de datos que permite relacionar dos datos arbitrarios entre sí y poder facilmente acceder a ellos.

Son objetos iterables mediante distintas formas, incluyendo la posibilidad de obtener una instancia de un Iterator.

Set

Los Set son otro tipo de estructura de datos que permite en este caso guardar valores arbitrarios, sin necesidad de una llave que sirva para acceder a estos. A cambio de no usar una llave para cada valor estos no se pueden repetir. Al igual que los Map estos son iterables.

WeakMap

Similar a un Map, con la diferencia de que no pueden ser iterados como un Map, no poseen el método clear para vaciarlos completamente y el key debe ser un objeto.

WeakSet

Similar a un Set, con laa diferencia de que no pueden ser iterador como un Set y no poseen el método clear para vaciarlos completamente. Solo se pueden guardar objetos.

Al no se iterables solo sirven para poder asignar objetos a valores boleanos que permite comprobar si un objeto está o no está en el WeakSet.

ECMAScript 7: El futuro no tan lejano

Ya desde el año pasado están en desarrollo algunas de las nuevas características que va a traer ECMAScript 7 la próxima versión de ES y de JS que en teoría debería estar lista en algún momento del año que viene (2016).

Object.observe() (draft)

Object.observe() (también llamado O.o()) es un nuevo método del objeto Object que permite realizar un single-way data-binding de un objeto de JavaScript. Este nuevo método es utilizado internamente por Polymer gracias a un polyfill.

Data-binding Revolutions with Object.observe() - HTML5 Rocks

¡Esta característica ya funciona en Google Chrome, Node.js e io.js!

Comas extras en parámetros de función (proposal)

En ES7 (y Babel ya tiene soporte) va a ser posible colocar una coma al final del último parámetro de una función (tanto al definir la función como al usarla) y que esta siga ejecutandose correctamente.

Esta característica haría los parámetros de funciones más consistentes con los objetos y arrays y facilitaría la generación automática de código (además que aunque parezca raro en varios lenguajes se usa).

Funciones asíncronas (proposal)

En ES7 (y Babel ya tiene soporte) se incorpora un nuevo tipo de función llamada función asíncrona. Estas se crean agregando la palabra async antes de function al momento de definirla.

Una función definida como asíncrona permite realizar cualquier tarea asíncrona (una petición HTTP por ejemplo) y esperar (await) hasta que se obtenga la respuesta para seguír con el código (esto funciona con otras funciones asíncrona o promesas, no con callbacks).

Ejecutar

Sintaxis de unión de funciones (proposal)

En ES7 (y Babel ya tiene soporte) se incorpora al lenguaje el operador :: el cual permitiría realizar un bind de dos funciones para simplificar la sintaxis.