![HenryLogo](https://d31uz8lwfmyn8g.cloudfront.net/Assets/logo-henry-white-lg.png)

Hacé click acá para dejar tu feedback sobre esta clase.

Hacé click acá completar el quiz teórico de esta lecture.
# ECMAScript 6 El ES6 ,también conocido como ECMAScript 2015 o ES2015+, es la última versión del standart. Este nuevo update es el primero desde que se estandarizó el lenguaje en 2009. Las implementaciones del nuevo standart todavía se están haciendo para varios motores de JavaScript. ## Historia Desde su aparición en 1995, JS fue evolucionando lentamente. ECMAScript apareció como standart en 1997, y desde ahí viene lanzando nuevas versiones como ES3, ES5, ES6, etc.. ![no-box](../_src/assets/03-ES6/jsevo.png) Como ven entre ES3 y ES5 pasaron _10 años_ y entre ES5 y ES6 pasaron _6 años_. Ahora la idea es lanzar nuevas versiones con cambios pequeños cada año. > Podemos ver un _mapa_ de las compatibilidades actuales de varios engines con respecto al nuevo standart [acá](http://kangax.github.io/compat-table/es6/) ![Compatibilidad](../_src/assets/03-ES6/es6-javascript-support.png) Como todavía no es compatible con muchos browsers, para poder utilizarlo vamos a utilizar una librería llamada `babel.js` que nos servirá para traducir código _ES6_ a la versión actual para así mantener compatibilidad con los engines actuales. Primero veamos algunas de las cosas que cambiaron en el nuevo standart. ## Nuevas Features ES6 incluye las siguientes features: - [let + const (Block Scoping)](#let--const) - [arrows =>](#arrows) - [classes](#classes) - [object literals mejorados](#enhanced-object-literals) - [template strings](#template-strings) - [destructuring](#destructuring) - [default + rest + spread](#default--rest--spread) - [iterators + for..of](#iterators--forof) - [generators](#generators) - [unicode](#unicode) - [modules](#modules) - [module loaders](#module-loaders) - [map + set + weakmap + weakset](#map--set--weakmap--weakset) - [proxies](#proxies) - [symbols](#symbols) - [subclassable built-ins](#subclassable-built-ins) - [promises](#promises) - [math + number + string + array + object APIs](#math--number--string--array--object-apis) - [binary and octal literals](#binary-and-octal-literals) - [reflect api](#reflect-api) - [tail calls](#tail-calls) - [Optional Chaining](#optional-chaining) ## ECMAScript 6 Features ### Let + Const `let` es el nuevo `var`. Sólo que let tiene un scope distinto, este está declarado sólo dentro del `bloque` donde aparece y no dentro del scope (por ejemplo si uso `let` dentro de un `for` no voy a poder ver esa variable afuera del mismo, está bien claro [acá](http://stackoverflow.com/questions/762011/let-keyword-vs-var-keyword-in-javascript)). `const` es para declarar variables inmutables o sea que no pueden cambiar. Si queremos asignar un nuevo valor a una variable declara con `const` vamos a obtener un Error. ```js function f() { { let x; { // okay, block scoped name const x = "sneaky"; // error, const x = "foo"; } // error, already declared in block let x = "inner"; } } ``` Más Info: [let statement](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let), [const statement](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const) ### Arrows Arrows (o flechas) son una forma de abreviar la declaración de una función y utiliza la sintaxis `=>` (está inspirada en sintaxis similares de C#, Java 8 y CoffeeScript). Estas soportan cuerpos que sean statements (ifs, fors, etc..) y también cuerpos que retornen el resultado de una expresion. A diferencia de las funciones normales, las funciones __arrows comparten el mismo `this` que el código que las rodea__. ```js // Cuerpos con Expresiones var pares = impares.map(v => v + 1); var nums = pares.map((v, i) => v + i); // Cuerpos con Statements nums.forEach(v => { if (v % 5 === 0) cincos.push(v); }); // this var bob = { _name: "Bob", _friends: [], printFriends() { this._friends.forEach(f => console.log(this._name + " knows " + f)); } } ``` Más información: [MDN Arrow Functions](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions) ### Classes Las clases en ES6 son simplemente syntax sugar sobre el patrón de prototipado de objetos. Tener una forma particular de declarar clases, hace que sea más fácil de usar y mejora la interoperabilidad. Las clases soportan la herencia basada en prototipos, llamadas a super, instance y métodos estáticos y constructores. ```js class SkinnedMesh extends THREE.Mesh { constructor(geometry, materials) { super(geometry, materials); this.idMatrix = SkinnedMesh.defaultMatrix(); this.bones = []; this.boneMatrices = []; //... } update(camera) { //... super.update(); } get boneCount() { return this.bones.length; } set matrixType(matrixType) { this.idMatrix = SkinnedMesh[matrixType](); } static defaultMatrix() { return new THREE.Matrix4(); } } ``` Más info: [MDN Classes](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes) ### Object Literals Mejorados Ahora los Object Literals se extendedieron para setear el prototipo durante su construcción, atajos para cuando hacemos una asignación de este tipo: `propiedad: propiedad`, definimos métodos, cuando hacemos llamadas a super, y al computar nombres de propiedades en una expresión. Todo esto junto mejora el proceso de diseño orientado a objetos ya que trabaja en sinergía con las mejoras en las clases antes mencionadas. ```js var obj = { // __proto__ __proto__: theProtoObj, //extiende el prototipo propiedad, // atajo para propiedad:propiedad // Methods toString() { // Super calls return "d " + super.toString(); }, // Computed (dynamic) property names [ 'prop_' + (() => 42)() ]: 42 }; ``` Más Info: [MDN Grammar and types: Object literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Object_literals) ### Template Strings Los Template Strings son una syntax sugar para la construcción de strings. Es parecido a la interpolación de stings de Perl, Python y otros lenguajes. ```js // Basic literal string creation `In JavaScript '\n' is a line-feed.` // Multiline strings `In JavaScript this is not legal.` // String interpolation var name = "Bob", time = "today"; `Hello ${name}, how are you ${time}?` // Construct an HTTP request prefix is used to interpret the replacements and construction POST`http://foo.org/bar?a=${a}&b=${b} Content-Type: application/json X-Credentials: ${credentials} { "foo": ${foo}, "bar": ${bar}}`(myOnReadyStateChangeHandler); ``` Más Info: [MDN Template Strings](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/template_strings) ### Destructuring Las estructuras se pueden desestructurar para poder seleccionar valores usando patrones de matcheo, con soporte para arreglos y objetos. Esto funciona igual que buscar una propiedad de un objeto `foo['bar']` en el sentido que ambos son `fail-soft`, es decir, que producen un `undefined` cuando algo no se encuentra. ```js // list matching var [a, , b] = [1,2,3]; // object matching var { op: a, lhs: { op: b }, rhs: c } = getASTNode() // object matching shorthand // binds `op`, `lhs` and `rhs` in scope var {op, lhs, rhs} = getASTNode() // Can be used in parameter position function g({name: x}) { console.log(x); } g({name: 5}) // Fail-soft destructuring var [a] = []; a === undefined; // Fail-soft destructuring with defaults var [a = 1] = []; a === 1; ``` Más Info: [MDN Destructuring assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) ### Default + Rest + Spread Las declaraciones de funciones pueden tener argumentos que defaultean a un valor si no son declarados. También se puede transformar un arreglo en argumentos consecutivos. Y al reves, o sea podemos bindear los últimos elementos de los argumentos como si fuera un sólo arreglo. ```js function f(x, y=12) { // y is 12 if not passed (or passed as undefined) return x + y; } f(3) == 15 ``` ```js function f(x, ...y) { // y is an Array return x * y.length; } f(3, "hello", true) == 6 ``` ```js function f(x, y, z) { return x + y + z; } // Pass each elem of array as argument f(...[1,2,3]) == 6 ``` Más Info: [Default parameters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters), [Rest parameters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters), [Spread Operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator) ### Iterators + For..Of Un objeto es un iterador cuando sabe como acceder a una colección de items de a uno, mientras mantiene su posición dentro de esa secuencia. En ES6 un iterador es cualquier cosa que provea un método `next()` que retorn el próximo item en la secuencia. También se generalizó el `for...in` para poder usar `for...of` en iteradores. ```js let fibonacci = { [Symbol.iterator]() { let pre = 0, cur = 1; return { next() { [pre, cur] = [cur, pre + cur]; return { done: false, value: cur } } } } } for (var n of fibonacci) { // truncate the sequence at 1000 if (n > 1000) break; console.log(n); } ``` Más info: [MDN for...of](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of) ### Generators Los iteradores son herramientas muy útiles, hay que tener mucho cuidado cuando los programamos porque necesitan mantener internamente su estado todo el tiempo. Los generadores nos proveen una alternativa poderosa: te dejan definir un algoritmo iterativo escribiendo una función que mantenga su propio estado. ```js function* idMaker(){ var index = 0; while(true) yield index++; } var gen = idMaker(); console.log(gen.next().value); // 0 console.log(gen.next().value); // 1 console.log(gen.next().value); // 2 // ... ``` Más info: [MDN Iteration protocols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) ### Unicode Hicieron adiciones para mejorar el soporte con Unicode. ```js // same as ES5.1 "𠮷".length == 2 // new RegExp behaviour, opt-in ‘u’ "𠮷".match(/./u)[0].length == 2 // new form "\u{20BB7}"=="𠮷"=="\uD842\uDFB7" // new String ops "𠮷".codePointAt(0) == 0x20BB7 // for-of iterates code points for(var c of "𠮷") { console.log(c); } ``` Más Info: [MDN RegExp.prototype.unicode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/unicode) ### Modules Ahora Javascript soporta módulos de forma nativa (antes era mediante `CommonJS`), es muy parecido ya que están basados en la filosofía de lo que ya veniamos usando. ```js // lib/math.js export function sum(x, y) { return x + y; } export var pi = 3.141593; ``` ```js // app.js import * as math from "lib/math"; alert("2π = " + math.sum(math.pi, math.pi)); ``` ```js // otherApp.js import {sum, pi} from "lib/math"; alert("2π = " + sum(pi, pi)); ``` Ahora podemos distinguir los __named exports__, que son básicamentes todos los que exporten una variable con un nombre, por ejemplo: `export var pi = 3.14;`. Podemos tener muchos de estos por archivo. También existe el __Default Export__: Sólo puede haber _uno_ por archivo, este es más parecido a la vieja forma de exportar. Generalmente lo usamos cuando, al importar, queremos que esté _todo_ dentro de un objeto y no importar _varios_ objetos separados. ```js // lib/mathplusplus.js export * from "lib/math"; export var e = 2.71828182846; export default function(x) { return Math.log(x); } ``` ```js // app.js import ln, {pi, e} from "lib/mathplusplus"; alert("2π = " + ln(e)*pi*2); ``` Más info: [import statement](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import), [export statement](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export) ### Map + Set + WeakMap + WeakSet Nuevas Estructuras de datos. En general basadas en estructuras muy usadas en otros lenguajes. ```js // Sets var s = new Set(); s.add("hello").add("goodbye").add("hello"); s.size === 2; s.has("hello") === true; // Maps var m = new Map(); m.set("hello", 42); m.set(s, 34); m.get(s) == 34; // Weak Maps var wm = new WeakMap(); wm.set(s, { extra: 42 }); wm.size === undefined // Weak Sets var ws = new WeakSet(); ws.add({ data: 42 }); // Because the added object has no other references, it will not be held in the set ``` Más Info: [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map), [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set), [WeakMap](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap), [WeakSet](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet) ### Subclassable Built-ins En ES6, objetos nativos como `Array`, `Date` y elementos del `DOM` pueden ser heredados por una subclase. Object construction for a function named `Ctor` now uses two-phases (both virtually dispatched): - Call `Ctor[@@create]` to allocate the object, installing any special behavior - Invoke constructor on new instance to initialize The known `@@create` symbol is available via `Symbol.create`. Built-ins now expose their `@@create` explicitly. ```js // Pseudo-code of Array class Array { constructor(...args) { /* ... */ } static [Symbol.create]() { // Install special [[DefineOwnProperty]] // to magically update 'length' } } // User code of Array subclass class MyArray extends Array { constructor(...args) { super(...args); } } // Two-phase 'new': // 1) Call @@create to allocate object // 2) Invoke constructor on new instance var arr = new MyArray(); arr[1] = 12; arr.length == 2 ``` ### Math + Number + String + Array + Object APIs Se agregaron cosas nuevas en las librerías nativas, incluyendo librerías matemáticas, funciones para convertir arreglos, funciones para trabajar Strings, y Object.assign para copiar objetos. ```js Number.EPSILON Number.isInteger(Infinity) // false Number.isNaN("NaN") // false Math.acosh(3) // 1.762747174039086 Math.hypot(3, 4) // 5 Math.imul(Math.pow(2, 32) - 1, Math.pow(2, 32) - 2) // 2 "abcde".includes("cd") // true "abc".repeat(3) // "abcabcabc" Array.from(document.querySelectorAll('*')) // Returns a real Array Array.of(1, 2, 3) // Similar to new Array(...), but without special one-arg behavior [0, 0, 0].fill(7, 1) // [0,7,7] [1, 2, 3].find(x => x == 3) // 3 [1, 2, 3].findIndex(x => x == 2) // 1 [1, 2, 3, 4, 5].copyWithin(3, 0) // [1, 2, 3, 1, 2] ["a", "b", "c"].entries() // iterator [0, "a"], [1,"b"], [2,"c"] ["a", "b", "c"].keys() // iterator 0, 1, 2 ["a", "b", "c"].values() // iterator "a", "b", "c" Object.assign(Point, { origin: new Point(0,0) }) ``` Más info: [Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number), [Math](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math), [Array.from](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from), [Array.of](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/of), [Array.prototype.copyWithin](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/copyWithin), [Object.assign](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) ### Binary y Octal Literals Dos nuevas formas literales agregadas para binario (`b`) y octal (`o`). ```js 0b111110111 === 503 // true 0o767 === 503 // true ``` ### Promises Promises es una librería para mejorar la programación asíncrónica. Las Promises son una representación de tipo first-class de un valor que va a estar disponible en el futuro. Esto también ya existia con otras librerías de terceros. ```js function timeout(duration = 0) { return new Promise((resolve, reject) => { setTimeout(resolve, duration); }) } var p = timeout(1000).then(() => { return timeout(2000); }).then(() => { throw new Error("hmm"); }).catch(err => { return Promise.all([timeout(100), timeout(200)]); }) ``` Más info: [MDN Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) ### Tail Calls Se puede implementar llamadas recursivas sin tener que agregar un un frame al `call stack` haciendo que sea segura la ejecución de una función recursiva (sin temer por el stack overflow). ```js function factorial(n, acc = 1) { 'use strict'; if (n <= 1) return acc; return factorial(n - 1, n * acc); } // Stack overflow in most implementations today, // but safe on arbitrary inputs in ES6 factorial(100000) ``` > Podemos ver una lista de features más detallada y comparada con la versión anterior [aquí](http://es6-features.org/) ### Optional Chaining El operador de encadenamiento opcional `?.` permite leer el valor de una propiedad ubicada dentro de una cadena de objetos conectados sin tener que validar expresamente que cada referencia en la cadena sea válida. El operador `?.` funciona de manera similar a el operador de encadenamiento `.` , excepto que en lugar de causar un error si una referencia es `null` o `undefined`, la expresión hace una short-circuit evaluation (`la evaluacion del segundo termino solo se efectua si el primero no permite definir un resultado ej: (true ||false)---> da verdadero sin siquiera pasar por false`) con un valor de retorno de `undefined`. Cuando se usa con llamadas a funciones, devuelve `undefined` si la función dada no existe. Esto da como resultado expresiones más cortas y simples cuando se accede a propiedades encadenadas dónde existe la posibilidad de que falte una referencia. También puede ser útil al explorar el contenido de un objeto cuando no hay una garantía conocida de qué propiedades se requieren. ```js const adventurer = { name: 'Alice', cat: { name: 'Dinah' } }; const dogName = adventurer.dog?.name; console.log(dogName); // expected output: undefined console.log(adventurer.someNonExistentMethod?.()); // expected output: undefined ``` ## Compatibilidad Para poder utilizar la sintaxis y las nuevas funcionalidad de ES6 en los motores no compatibles, vamos a utilizar [Babel.js](https://babeljs.io/) Para instalarlo: ```bash # install the cli and this preset npm install --save-dev @babel/core @babel/cli # make a .babelrc (config file) with the preset npm install @babel/preset-env echo '{ "presets": ["@babel/preset-env"] }' > .babelrc # create a file to run on echo 'console.log([1, 2, 3].map(n => n + 1));' > index.js # run it ./node_modules/.bin/babel-node index.js ``` De esa forma vamos a poder transformar un archivo y lo tenemos que hacer manualmente. Si queremos que sea automático tenemos muchísimas opciones. Veamos algunas en la página de [babel](https://babeljs.io/docs/setup/) y elijamos el setup que más nos guste. ## Homework Completa la tarea descrita en el archivo [README](../03-ES6/homework/README.md)