Skip to content

Instantly share code, notes, and snippets.

@hlrd93
Last active January 19, 2017 05:18
Show Gist options
  • Save hlrd93/32ddb4dcd2dd40a560cc075b90ed2702 to your computer and use it in GitHub Desktop.
Save hlrd93/32ddb4dcd2dd40a560cc075b90ed2702 to your computer and use it in GitHub Desktop.
ES6
#**ES6:** *Primer Episodio*
###Introducción
Brendan Eich en 1995 crea un lenguaje llamado Mocha, cuando trabajaba en **Netscape**, luego en septiembre del mismo año cambia de nombre a **LiveScript**, hasta que cambiaron el nombre a **JavaScript** debido a una comercialización, ya que **Netscape** fue adquirido por **Sun Microsystems**, propietario del Lenguaje **Java**, muy popular para ese entonces.
Más tarde en 1997 se crea la ***ECMA (European Computer Manufacturers Association)***, comité para estandarizar *JavaScript*, dicho estándar está diseñado para evitar incompatibilidades entre navegadores y desde entonces las normas *JavaScript* están regidas por *ECMAScript*.
A inicio de 1999, se obtiene la tercera versión de la norma *ECMAScript*, que seguiría siendo válida unos años más, luego se le realizaron pequeños intentos para escribir la versión 4, pero fue hasta 2011 que la versión 5 (ES5) fue aprobada y estandarizada.
Posteriormente en 2013 el proyecto de la versión 6 fue detenido hasta diciembre de 2014 cuando finalmente fue aprobado y estandarizado en junio de 2015, siendo *ECMAScript2015* la última versión del lenguaje de programación *JavaScript* para la web, enfocado en la simplicidad y la legibilidad, fue nombrado ES6 y puede ser usado en los navegadores modernos.
Echa un vistazo a estos enlaces:
>*ECMAscript/ES6 features*
>https://github.com/lukehoban/es6feature
>*Compatible table of browsers with ECMAscript2015*
>http://kangax.github.io/compat-table/es6/
>*Intro ECMAscript2015/ES6*
>https://medium.com/ecmascript-2015/let-s-talk-about-javascript-ecmascript-2015-es6-say-hello-world-658ce6941
###Prerequisitos
So, let's get started:
Install node from:
>https://nodejs.org/en/
***Or*** follow this guide:
You should have some familiarity with the Linux terminal since you’ll need to use it to install and test Node and NPM. You’ll also need the terminal to use Node.js and NPM.
Dependencies. You need to install a number of dependancies before you can install Node.js and NPM.
Ruby and GCC. You’ll need Ruby 1.8.6 or newer and GCC 4.2 or newer.
For Ubuntu or Debian-based Linux distributions, run the following command in your terminal:
>***$*** sudo apt-get install build-essential curl git m4 ruby texinfo libbz2-dev libcurl4-openssl-dev libexpat-dev libncurses-dev zlib1g-dev
Then select Y to continue and wait for the packages to be installed.
For Fedora based Linux distributions run the following command in your terminal application:
>***$*** sudo yum groupinstall 'Development Tools' && sudo yum install curl git m4 ruby texinfo bzip2-devel curl-devel expat-devel ncurses-devel zlib-devel
Then select Y to continue and wait for the packages to be installed.
Homebrew. Homebrew is a package manager originally for the Mac, but it’s been ported to Linux as Linuxbrew, making installing most open-source software (like Node) as simple as writing: brew install node You can learn more about Homebrew at the Homebrew website and Linuxbrew at the Linuxbrew website.
To install Homebrew for Linux, open your terminal application and paste in the command:
> ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/linuxbrew/go/install)"
Follow the instructions in the terminal to complete the installation process.
Once Linuxbrew is installed, you’ll need add the following 3 lines to your ***~/.bashrc*** or ***~/.zshrc*** file:
>`export PATH="$HOME/.linuxbrew/bin:$PATH"
>export MANPATH="$HOME/.linuxbrew/share/man:$MANPATH"
>export INFOPATH="$HOME/.linuxbrew/share/info:$INFOPATH"`
####Why Homebrew/Linuxbrew?
You may be asking why you should use a third-party package manager. Here are some advantages:
- Can install software to a home directory and so does not require sudo.
- Install software not packaged by the native distribution.
- Install up-to-date versions of software when the native distribution is old.
- Use the same package manager to manage both your Mac and Linux machines.
#**ES6:** *Second episode*
###Installation
Installing Node.js and NPM is pretty straightforward using Linuxbrew, the Linux port of Homebrew. It handles downloading, unpacking, compiling, and installing Node and NPM on your system. After you have Linuxbrew installed, the whole process should only take you a few minutes.
Open up your terminal and type
>***$*** brew install node.
Sit back and wait. Homebrew has to download some files, compile and install them. But that’s it.
Then open a new terminal:
run command ***node*** like this:
>$ node
> `>`let h = "Hello DailyDrip"
> `>`
> `>`console.log(h)
'Hello DailyDrip'
###ES6 Sintaxis
Juguemos con **REPL** ( Read Eval Print Loop )
Tenemos las nuevas sintaxis *ES6*
### **Template Strings:**
*Template strings* son cadenas literales de texto que se encuentran incrustadas en el código fuente.
Con la nueva versión *ES6* se nos permite interpolar *strings* de una manera más sencilla de lo que hemos hecho hasta ahora.
####**Sintaxis:**
Consta de dos aspectos fundamentales:
- Las **comillas invertidas** (`), se usan para determinar las cadenas
- El **signo de dólar** ($) seguido de **llaves** {}, se usan para añadir marcadores de posición.
Por ejemplo:
```javascript
//ES6
let object1 = "JavaScript";
let object2 = "increíble";
console.log(`Sólo quiero decir que ${object1} es ${object2`);
// Solo quiero decir que JavaScript es increible
```
#####**Multi-line Strings**
En *JavaScript* se puede hacer uso de *multi-line strings*, en la versión *ES5* nosotros podíamos tener estas *multi-line strings* concatenando con +.
Podemos ver la diferencia entre la versión anterior y la nueva versión *ES6*.
Ejemplo:
```javascript
//ES5
var saludo = "Hola " +
"como " +
"estas? ";
```
```javascript
//ES6
var saludo = "Hola
como
estas?";
console.log("Hola
como
estas?");
```
>***nota:***
>El *template strings* mantiene el formato introducido que incluye los saltos de línea y las tabulaciones.
#####**String Interpolation**
*Interpolation string* permite incrustar expresiones dentro de cadenas normales. Toda expresión válida en el lenguaje lo es en la plantilla.
Por ejemplo:
***Arrays***
```javascript
//Arrays
var italian = [ 'la', 'donna', 'e', 'mobile' ];
console.info( `My chain joined: ${ italian.join( ' ' ) }` );
// My chain joined: la donna e mobile
```
***Objects***
```javascript
// Objects
var biblioteca = [
{ id: 1,
titulo: 'Harry Potter'},
{ id: 2,
titulo: 'El Secreto' }
];
var myID = 2;
console.info( `Titulo del libro: ${ biblioteca.find( item => item.id === myID ).titulo }` );
// Titulo del libro: El Secreto
```
***Methods***
```javascript
// Methods
var frase = 'La casa es grande';
console.info( `Mayúsculas: ${ frase.toUpperCase() }` );
// Mayúsculas: LA CASA ES GRANDE
```
***Maths***
```javascript
//Maths
var valor1 = 1000,
valor2 = 200;
console.info( `La suma: ${ valor1 + valor2 }` );
// 1200
```
***Ternary Operator***
```javascript
//Ternary Operator
var libro = {
id: 10,
titulo: falso,
año: 2011
};
console.info( `Informe del libro: ${ libro.titulo ? libro.titulo : 'Falta título del libro!' }` );
// Informe del libro: Falta título del libro!
```
***Logical operators***
```javascript
//Logical operators
var libro = {
id: 11,
titulo: 'Narnia',
años: falso
};
console.info( `Año del libro: ${ libro.año || 'Desconocido' }` );
// Año del libro: Desconocido
```
#####**Postprocessing Templates**
Una función de *postprocessing*, es una forma más avanzada de *template strings*, es lo que se conoce como una función de tipo *quasi-parser*, con la que se puede lograr modificar la salida de las plantillas, haciendo uso de una función.
Ejemplo:
```javascript
var tag = strings => console.log(strings);
tag`Hola Mundo`;
// [ "Hola mundo" ]
```
La función ***`tag`*** llamada *quasi-parser* es la encargada de recoger un parámetro ***`'string'`*** dando como salida ese mismo valor. Al hacer el llamado a la función en lugar de utilizar los **paréntesis** como habitualmente se hace, lo hacemos con una plantilla de texto *(quasi-quotation)*.
Se tiene como resultado, que ***`tag`*** recibe la plantilla como argumento y lo muestra en pantalla.
Por ejemplo:
```javascript
var tag = funcion ( strings ) {
return strings;
};
var result = tag`Hola Mundo`;
console.info( result );
// [ "Hola Mundo" ]
```
Así la función recoge los literales y la interpolación se consigue a través del resto de parámetros:
```javascript
var tag = funcion ( strings, ...values ) {
console.info( strings );
console.info( values );
};
var name = 'Carlos',
city = 'Canada';
tag`Hola ${ name }, bienvenido a ${ city }!`;
// [ "Hola ", ", bienvenido a ", "!" ]
// [ "Carlos", "Canada" ]
```
Se puede notar que se ha añadido un argumento nuevo a la función ***`tag`***, básicamente lo que se ha hecho es agrupar todos los que llegan a partir del segundo haciendo uso del operador arrastre, y ese ***`array`*** recoge los valores que se obtienen de la interpolación.
### **Block scoping:** **var** *vs* **let** *vs* **const**
Como consecuencia del poco tiempo en el que se desarrolló el lenguaje *JavaScript*, no tenía *Block Scoping*, siendo ***`var`*** la única palabra clave asignable para las variables hasta ahora, con la nueva versión *ES6*, se ofrecen dos nuevas formas para la declaración de variables en *JavaScript*: ***`let`*** y ***`const`***.
>***nota:***
> 1. Se usa ***`const`*** por defecto.
> 2. Se usa ***`let`*** si se tiene que volver a vincular una variable.
>3. Se usa ***`var`*** para señalar el código heredado intacto.
####**Sintaxis:**
####**let:**
Una de las nuevas características de *ES6* es ***`let`***, que nos permite declarar variables limitando su *scope* al bloque, declaración o expresión donde se está usando, la cual, opcionalmente puede ser inicializada con algún valor.
Esto es lo que diferencia la expresión ***`let`*** de la palabra reservada ***`var`***, la cual define una variable global o local en una función sin importar el ámbito del bloque.
Ejemplo:
**If Block**
```javascript
//if
(function(){
var vegetal = "Zanahoria";
if(true){
console.log(vegetal);
let vegetal = "Papa";
console.log(vegetal);
//Papa
}
console.log(vegetal);
//Zanahoria
})();
```
Se puede ver en el ejemplo que cuando usamos ***`let`*** dentro de un bloque, se puede limitar el alcance de la variables a dicho bloque, se puede notar la diferencia ***`a`*** con ***`var`***, cuyo alcance reside dentro de la función donde ha sido declarada la variable.
**For loop block **
```javascript
for(let i = 0; i < 30; i++){
console.log(i);
}
console.log("outside" + i);
//Indefinido
for(var i = 0; i < 30; i++){
console.log(i);
}
console.log("outside" + i);
//30
```
Se puede ver en este ejemplo el uso de la palabra reservada ***`let`*** para enlazar variables con alcance local dentro del alcance de un bucle en lugar de usar una variable global para dicho propósito.
####**const:**
***`Const`*** es la otra nueva característica de ES6 para la declaración de variables, la declaración del ***`const`*** crea una constante que puede ser global o local a la función en la que se declara, es decir, es necesario inicializar la constante, especificando su valor en la misma sentencia en la que se declara, dicho valor no puede cambiarse a través de la reasignación, y no se puede redeclarar.
Ejemplo:
```javascript
const varname1 = value1 [, varname2 = value2 [, varname3 = value3 [, ... [, varnameN = valueN]]]];
```
>***nota:***
>Al declararse una ***`const`*** se crea una referencia de solo lectura, esto no significa que dicho valor sea inmutable, sino que el identificador de la variable no puede ser reasignado, en el caso de que la asignación a la constante sea un objeto, el objeto si puede ser alterado.
>
> Una constante no puede compartir su nombre con una función o variable en el mismo ámbito.
>
>Los ***`integer`***, ***`strings`***, ***`booleans`***, ***`symbols`***, ***`null`*** o ***`undefined`***, es decir los valores primitivos, siempre son inmutables.
####**var:**
Las variables *JavaScript* son contenedores para el almacenamiento de valores de datos.
Ejemplo:
```javascript
var A = 20;
var B = 50;
var C = A + B;
// A almacena el valor 20
// B almacena el valor 50
// Entonces C el valor 70
```
Toda variable *JavaScript* debe ser identificada con nombres únicos llamados *identificadores*, que pueden ser nombres cortos como letras o nombres más descriptivos como alguna característica (nombre, edad...).
>***nota:***
>El uso de ***`var`*** fuera de una función es algo opcional, el asignarle un valor a una variable no declarada implica que se declara como variable global.
```javascript
var varname1 [= value1 [, varname2 [= value2 ...[, varnameN [= valueN ']]]]];
```
>***nota:*** Siempre se recomienda usar ***`var`***, es necesario dentro de las funciones en la siguiente situación:
>1. Cuando una variable en un ámbito contiene la función incluyendo también el ámbito global y esta tiene el mismo nombre.
>2. Cuando varias funciones o funciones recursivas usan variables con un mismo nombre y tienen la intención de ser locales.
>3. Cuando al no declarar las variables en estos casos puede desembocar en resultados no deseados.
###**Functions**
Desde la creacion del lenguaje *JavaScript* las *functions* no habían cambiado mucho, para la nueva versión de *ECMAScript 6* las *functions* dan un gran salto hacia adelante, y se tiene como resultado una serie de mejoras que hace la programacion en *JavaScript* menos propensa a errores y más flexible.
###**Rest Parameters**
*Rest* es un parámetro expresado por tres puntos **(...)** que preceden a un parámetro con nombre, convirtiendose en un *array* que contiene el resto de los parámetros pasados a la función.
Ejemplo: ***`pick ()`*** puede ser reescrito utilizando el parámetro ***`rest`***
```javascript
function pick(object, ...keys) {
let result = Object.create(null);
for (let i = 0, len = keys.length; i < len; i++) {
result[keys[i]] = object[keys[i]];
}
return result;
}
```
>***nota:***
>Los parámetros de reposo no afectan a la propiedad de longitud de una función, que indica el número de parámetros nombrados para la función.
El valor de length para pick () en este ejemplo es 1 porque sólo el objeto cuenta para este valor.
**Rest Parameter Restrictions** cuenta con dos *restrictions*:
1.- Sólo puede haber un parámetro ***`rest`***, y el parámetro restante debe ser el último.
Por ejemplo: Este código no funcionará
```javascript
// Syntax error: Can't have a named parameter after rest parameters
function pick(object, ...keys, last) {
let result = Object.create(null);
for (let i = 0, len = keys.length; i < len; i++) {
result[keys[i]] = object[keys[i]];
}
return result;
}
```
2.- Los parámetros ***`rest`*** no se pueden usar en un *object literal* ***`setter`***.
Ejemplo: Este código causa un error de sintaxis
```javascript
let object = {
// Syntax error: Can't use rest param in setter
set name(...value) {
// do something
}
};
```
>***nota:***
> -Los parámetros ***`rest`*** fue diseñado para reemplazar argumentos en *JavaScript*.
> -El argumento *object* trabaja junto con el parámetro ***`rest`*** al reflejar los argumentos que se pasaron a la función cuando se le llamó.
>
> -De esta forma el parámetro ***`rest`*** afecta el argumento *object*.
como se ilustra en el siguiente ejemplo:
```javascript
function checkArgs(...args) {
console.log(args.length);
console.log(arguments.length);
console.log(args[0], arguments[0]);
console.log(args[1], arguments[1]);
}
checkArgs("a", "b");
```
La llamada de ***`checkArgs ()`*** da como resultado:
```javascript
2
2
a a
b b
```
###**The Spread Operator**
El *spread operator* se encuentra muy relacionado con el parámetro *rest*. Permite especificar la division de un *array* y pasa los argumentos separados a una función mientras que el parámetro *rest* especifica argumentos independientes que deben combinarse en un *array*.
El uso del método ***`Math.max ()`*** debe ser incorporado, puesto que acepta cualquier número de argumentos y devuelve el de mayor valor.
Ejemplo:
```javascript
let value1 = 25,
value2 = 50;
console.log(Math.max(value1, value2));
// 50
```
Se puede observar que se pasan los dos valores pero el de mayor valor es el que se devuelve.
Si quieres que sea devuelto el valor mas pequeño por el método ***`Math.max ()`*** se pasa el argumento por separado y se sigue usando el operador *spread* para los demás argumentos.
Ejemplo:
```javascript
let values = [-25, -50, -75, -100]
console.log(Math.max(...values, 0));
// 0
```
>***nota:***
>*ES6* puede aplicar tanto el parámetro *rest* como los *default parameters* a la función *builder* de *JavaScript*.
###**Arrow Functions:**
Las *arrow functions* son, como su nombre indica, funciones definidas con una nueva sintaxis que utiliza una flecha ***`(=>)`***.
Es una nueva forma de escribir funciones anónimas, siendo esta una nueva sintaxis en la versión final de las normas *ES6*. Es un cambio sencillo que nos permite una manera más rápida y límpia de crear una función anónima, así como también, ahorrar tiempo y simplificar el desarrollo en el ámbito de la función.
En la versión anterior *ES5* una función anónima se escribía como esto:
```javascript
// ES5
var AddAB = function (A, B) {
return A + B;
}
```
Esto no parece demasiado largo, sin embargo, ahora podemos acortar aún más nuestro código con la nueva forma *ES6* a esto:
```javascript
// ES6
var AddAB = (A, B) => A + B;
```
Algo interesante de *arrow functions* es el uso del ***`this`***, estas cambian la forma en que ***`this`*** se une en las funciones.
***nota:***
>Después de los parámetros, es donde se pone la flecha seguida de la variable que hemos pasado.
>Hemos sido capaces de dejar de lado la instrucción de retorno, ya que dicho retorno se sobre entiende al escribirlo de esta forma.
>Se puede eliminar la necesidad del ***`bind this`*** a la función.
####**Limitaciones:**
Sin embargo las *arrow function* se comportan de manera diferente a las funciones tradicionales de *JavaScript* de ciertas formas importantes:
1. ***`super`***, ***`arguments`***, and ***`new.target`*** , estos valores dentro de la función son definidos por el más cercano que contiene la arrow function.
2. No se puede llamar nuevas *arrow function* a las que no tienen un método ***[[Construir]]*** y por lo tanto no se pueden utilizar como constructores, de ser así generan error.
3. No es necesario hacer uso de prototipos para las *arrow funtions*, ya que los prototipos no existen para *arrow function*.
4. No puedes cambiar el valor que se encuentra dentro de la función. Dicho valor seguira siendo el mismo durante todo el ciclo de vida de la función.
5. Sin *argument object* las *arrow functions* no tienen ningún enlace de argumentos, debe confiar en los parámetros ***`name`*** y ***`rest`*** para acceder a los argumentos de la función.
6. No hay nombres de parametros duplicados con ***`name`*** de modo estricto o no estricto, en contraposición a las *arrow function*, que no pueden tener duplicados sólo los parámetros nombrados en modo estricto.
####**Sintaxis:**
La sintaxis para las *arrow functions* viene de varias formas dependiendo de qué se está tratando de lograr. Todas las variaciones comienzan con los argumentos de la función, seguido por la flecha, seguido por el cuerpo de la función.
Los argumentos y el cuerpo pueden tomar diferentes formas dependiendo del uso.
Por ejemplo:
La siguiente *arrow function* toma un solo argumento y simplemente lo devuelve:
```javascript
let reflejar = value => value;
// Efectivamente equivalente a:
let reflejar = function(value) {
return value;
};
```
Si está pasando más de un argumento, debe incluir paréntesis alrededor de esos argumentos, por ejemplo:
```javascript
let suma = (objeto1, objeto2) => objeto1 + objeto2;
// Efectivamente equivalente a:
let suma = function(objeto1, objeto2) {
return objeto1 + objeto2;
};
```
Si no hay argumentos para la función, debe incluir un conjunto de paréntesis en la declaración, por ejemplo:
```javascript
let getNombre = () => "DailyDrip.com";
// Efectivamente equivalente a:
let getNombre = function() {
return "DailyDrip.com";
};
```
Cuando deseas proporcionar una función tradicional y consistente en más de una expresión, necesitas envolver el cuerpo de la función en *curly braces,* y definir explícitamente un valor de retorno, como en esta versión de *ES6* para ***`sum ()`*** :
```javascript
let suma = (numero1, numero2) => {
return numero1 + numero2;
};
// Efectivamente equivalente a:
let suma = function(numero1, numero2) {
return numero1 + numero2;
};
```
Si desea crear una función que no hace nada, debe incluir *curly braces,* por ejemplo:
```javascript
let doNothing = () => {};
// Efectivamente equivalente a:
let doNothing = function() {};
```
**Syntax quirks**
>Puntos a tomar en cuenta con respecto a la sintaxis.
> 1- ` => ` No se pueden usar como funciones constructoras, porque la nueva forma de escribirla genera un error.
```javascript
new ()=>{} // invalid
new (()=>{}) // invalid
```
> 2- El salto de línea después de los parámetros no es válido en las *arrow functions*, solo es válido definido en el interior del parámetro.
```javascript
const function1 = (A, B) // SyntaxError
=> {
return A + B;
};
const function2 = (A, B) => // OK
{
return A + B;
};
const function3 = (A, B) => { // OK
return A + B;
};
const function4 = (A, B) // SyntaxError
=> A + B;
const function5 = (A, B) => // OK
A + B;
// Los saltos de línea dentro de las definiciones de parámetros estan bien:
const func6 = ( // OK
A,
B
) => {
return A + B;
};
```
###**Object Literals**
*Object Literals* es algo que a los desarrolladores de *JavaScript* les es muy familiar si han trabajado con *JSON* ya que este se basa en su sintaxis; *object literals* es uno de los patrones más populares en *JavaScript*.
*ECMAScript 6* hace que los *object literals* sean más potentes e incluso más sucintos mediante la extensión de la sintaxis de varias maneras.
####**Sintaxis**
**Property Initializer Shorthand**
Anteriormente la expresión que representaba las *Property Initializer Shorthand* era de la siguiente manera.
Ejemplo:
```javascript
//ES5
function createEspecies(name, tipe) {
return {
name: name,
tipe: tipe
};
}
```
La función ***`createEspecies ()`*** crea un objeto cuyos nombres de las propiedades son igual que los nombres de los parámetros de la función. La clave ***`name`*** en el objeto devuelto es asignado al valor que contiene la variable ***`name`***, y el valor de la clave ***`tipe`*** en el objeto devuelto se le asigna el valor contenido en la variable ***`tipe`***.
***`createEspecie ()`*** se puede volver a escribir de la siguiente manera para *ECMAScript6* :
```javascript
//ES6
function createEspecies(name, tipe) {
return {
name,
tipe
};
}
```
En este ejemplo, el nombre de la propiedad *object literals* se asigna al valor del ***`name`*** de la variable local, dicha asignación es un patrón muy común en *JavaScript*.
**Concise Methods**
Para expresar *concise methods* en *ECMAScript5* y anteriores, se debía especificar un nombre y, a continuación definir la función completa para agregarle un método a un objeto.
Por ejemplo:
```javascript
//ES5
var mascota = {
name: "Duck",
sayNombre: function() {
console.log(this.nombre);
}
};
```
En la versión *ES6* se simplifica la sintaxis haciéndola más corta por eso es llamada sintaxis de *concise methods*, eliminando los dos puntos y la palabra clave "función".
Por ejemplo:
```javascript
//ES6
var mascota = {
nombre: "Duck",
sayNombre() {
console.log(this.nombre);
}
};
```
>***nota:***
> La propiedad nombre de un método creado utilizando la abreviatura de *concise methods* es el nombre antes de los paréntesis.
**Computed Property Names**
Para la versión *ES5* estas propiedades fueron fijadas con corchetes en vez de la notación del punto, por la siguiente razón, los corchetes permiten especificar los nombres de las propiedades usando *vars* y *string literals* que pueden contener caracteres que causan error de sintaxis.
Ejemplo:
```javascript
var estudiante = {},
apellido = "apellido";
estudiante["primer nombre"] = "Angela";
estudiante[apellido] = "Alvarez";
console.log(estudiante["primer nombre"]);
console.log(estudiante[apellido]);
// "Angela"
// "Alvarez"
```
Se puede también hacer uso de *string literals* de una forma directa como una propiedad *nombre* en *object literals*.
Ejemplo:
```javascript
//ES5
var estudiante = {
"primer nombre": "Angela"
};
console.log(estudiante["primer nombre"]);
// "Angela"
```
Para *ES6* usan igualmente los corchetes para referenciar *nombres* de propiedades calculadas en instancias de objeto.
Por ejemplo:
```javascript
//ES6
let apellido = "apellido";
let estudiante = {
"primer nombre": "Angela",
[apellido]: "Alvarez"
};
console.log(estudiante["primer nombre"]);
console.log(estudiante[apellido]);
// "Angela"
// "Alvarez"
```
También incluye expresiones donde los corchetes dentro del *object literal* indican que la propiedad *nombre* se calcula, por lo que su contenido se evalúan como una cadena.
Ejemplo:
```javascript
var suffix = " nombre";
var estudiante = {
["primero" + suffix]: "Angela",
["segundo" + suffix]: "Alvarez"
};
console.log(estudiante["nombre"]);
console.log(estudiante["apellido"]);
// "Angela"
// "Alvarez"
```
Cualquier cosa que se ponga dentro de los corchetes mientras se utiliza la notación de corchete en las instancias de objeto también trabaja para la propiedad *nombres* computados dentro de literales de objetos.
####**New Methods**
Actualmente *ECMAScript 6* introduce un par de nuevos métodos en el objeto global que están diseñados para hacer ciertas tareas más fáciles.
**The Object.is() Method**
Cuando se desea comparar dos valores en *JavaScript*, es probable que se utilicen el operador igual ***(==)*** o el operador idénticamente igual ***(===)***. Aunque la preferencia por la exactitud lleva a los desarrolladores a usar el operador idénticamente igual este no es tan exacto como se quisiera es por esto que *ECMAScript 6* introduce el método ***`Object.is ()`*** para solucionar este problema.
Con este método se aceptan dos argumentos y se devuelve *true* si los valores son equivalentes. Dos valores son considerados equivalentes cuando son del mismo tipo y tienen el mismo valor.
Por ejemplo:
```javascript
console.log(+0 == -0); // true
console.log(+0 === -0); // true
console.log(Object.is(+0, -0)); // false
console.log(NaN == NaN); // false
console.log(NaN === NaN); // false
console.log(Object.is(NaN, NaN)); // true
console.log(3 == 3); // true
console.log(3 == "3"); // true
console.log(3 === 3); // true
console.log(3 === "3"); // false
console.log(Object.is(3, 3)); // true
console.log(Object.is(3, "3")); // false
```
**The Object.assign() Method**
***`Object.assign ()`*** se encarga de aceptar cualquier número de *supplier* y el receptor recibe las propiedades en el orden en que se especifican, es decir, el ultimo *supplier* podría sobrescribir un valor del primer *supplier* en el receptor.
Ejemplo:
```javascript
var receiver = {};
Object.assign(receiver,
{
type: "js",
name: "file.js"
},
{
type: "css"
}
);
console.log(receiver.type); // "css"
console.log(receiver.name); // "file.js"
```
El valor de *receiver.type* es ***`"css"`*** porque el segundo *supplier* sobrescribió el valor del primero.
El método ***`Object.assign ()`*** no es una adición significativa a *ECMAScript 6*, pero sí formaliza una función común que se encuentra en muchas librerias de *JavaScript*.
###**Destructuring:**
En *JavaScript* los *objects* y los *arrays* son dos de las anotaciones más usadas, gracias al formato de datos de JSON se han convertido en una parte importante del lenguaje. *ECMAScript 6* simplifica esta tarea añadiendo *destructuring*, que es el proceso de descomponer la estructura de datos en partes más pequeñas.
####**Arrays destructuring:**
Existe mucha similitud entre *array destructuring* y *object destructuring*, la diferencia es que, la *destructuring* opera en posiciones dentro de un *array* en lugar de las propiedades nombradas que están disponibles en *objects*.
Por ejemplo:
```javascript
let colors = [ "red", "green", "blue" ];
let [ firstColor, secondColor ] = colors;
console.log(firstColor); // "red"
console.log(secondColor); // "green"
```
Se puede observar la desestructura del *array* al sacar los valores ***`"rojo"`*** y ***`"verde"`*** del *array* de colores, que son almacenados en las variables ***`firstColor`*** y ***`secondColor`***.
Estos valores se eligen debido a su posición en el *array*; el nombre actual de las variables podrían ser cualquier cosa, pero los *items* no mencionados explícitamente en el patrón de *destructuring* se ignoran.
***nota:***
>Se debe tomar en cuenta que el *array* no es cambiado de ninguna manera
>Omitir elementos del patrón de desestructuración y el nombre de las variables para los elementos que le interesan, es algo que se puede hacer.
>Si solo se necesita el tercer valor del *array* no es necesario proporcionar nombres a la primera y segunda variable.
>De forma similar a la desestructuración de objetos, siempre se debe proporcionar un inicializador al usar *array destructuring* con *var*, *let*, o *const*.
Para asignar una *destructuring* no es necesario envolver la expresión entre paréntesis.
Por ejemplo:
```javascript
let colors = [ "red", "green", "blue" ],
firstColor = "black",
secondColor = "purple";
[ firstColor, secondColor ] = colors;
console.log(firstColor); // "red"
console.log(secondColor); // "green"
```
**Destructuring Assignment** de *arrays* tiene un caso de uso específico que facilita el intercambio de valores de dos variables. Para la forma *ECMAScript5* implica una variable extra *temporal*, que es necesaria para intercambiar los valores A y B.
Por ejemplo:
```javascript
// ES5
let A = 10,
B = 20,
tmp;
tmp = A;
A = B;
B= tmp;
console.log(A); // 20
console.log(B); // 10
```
Mientras que para la versión *ECMAScript 6* la asignación *destructuring* del *array*no hay necesidad de extraer las variables.
Ejemplo:
```javascript
// ES6
let A = 10,
B = 20;
[ A, B ] = [ B, A ];
console.log(A); // 20
console.log(B); // 10
```
**Default Values** son permitidos por la *destructuring* de *arrays* para cualquier posición en el *array*, dicho *default values* se usa cuando la propiedad dada no existe o tiene el valor ***`undefined`***.
Ejemplo:
```javascript
let colors = [ "red" ];
let [ firstColor, secondColor = "green" ] = colors;
console.log(firstColor); // "red"
console.log(secondColor); // "green"
```
**Disorganization of nested arrays** es de una manera similar a la destrucción de los objetos anidados, al insertar otro patrón de *arrays* en el patrón general, la *destructuring* desciende en un *array* anidado.
Por ejemplo:
```javascript
let colors = [ "red", [ "green", "lightgreen" ], "blue" ];
// later
let [ firstColor, [ secondColor ] ] = colors;
console.log(firstColor); // "red"
console.log(secondColor); // "green"
```
**Rest Items**
*Rest items* utilizan la sintaxis para asignar los elementos restantes de una matriz a una variable particular, donde el primer elemento de colores se asigna a ***`firstColor`*** y los restantes se asignan a una nueva matriz ***`restColors`*** que tiene los elementos *"green"* and *"blue"*.
Por ejemplo:
```javascript
let colors = [ "red", "green", "blue" ];
let [ firstColor, ...restColors ] = colors;
console.log(firstColor); // "red"
console.log(restColors.length); // 2
console.log(restColors[0]); // "green"
console.log(restColors[1]); // "blue"
```
>***nota:***
>Estos elementos *rest* se usan para extraer ciertos elementos de un *array* y mantener el resto disponible.
>Los arreglos de *JavaScript* tienen la capacidad de crear fácilmente un clon, usando el método ***`concat ()`*** como una forma fácil de clonar una matriz.
>En *ES6* se puede hacer uso del elemento *rest* para lograr la misma tarea mediante la sintaxis destinada a funcionar de esa manera.
Ejemplo:
```javascript
// cloning an array in ECMAScript 6
let colors = [ "red", "green", "blue" ];
let [ ...clonedColors ] = colors;
console.log(clonedColors);
// "[red,green,blue]"
```
>***nota:***
>Incluir una coma después de los elementos de resto es un error de sintaxis.
>Los elementos *rest* no deben ser la última entrada de la matriz desestructurada y no pueden estar seguidos por una coma.
####**Object Destructuring**
La *object destructuring* utiliza un *object literal* en el lado izquierdo de una operacion de asignacion.
Ejemplo:
```javascript
let node = {
type: "Identifier",
name: "foo"
};
let { type, name } = node;
console.log(type);
// "Identifier"
console.log(name);
// "foo"
```
Se puede observar el valor de ***`node.type`*** y de ***`node.name`*** que se almacenan en una variable llamada ***`name`***.
**Destructuring Assignment**
Los ejemplos de desestructuración de objetos que has visto hasta ahora han utilizado declaraciones de variables.
Sin embargo, también es posible usar la desestructuración en las asignaciones.
Por ejemplo, puede decidir cambiar los valores de las variables después de haberlas definido, de la siguiente manera:
let node = {
type: "Identifier",
name: "foo"
},
type = "Literal",
name = 5;
// assign different values using destructuring
({ type, name } = node);
console.log(type); // "Identifier"
console.log(name); // "foo"
En este ejemplo, el tipo y el nombre se inicializan con valores cuando se declaran y, a continuación, dos variables con los mismos nombres se inicializan con valores diferentes.
La siguiente línea usa asignaciones de desestructuración para cambiar esos valores leyendo desde el objeto de nodo.
Tenga en cuenta que debe poner paréntesis alrededor de una declaración de asignación de desestructuración.
La razón es que una abrazadera de apertura se espera que sea una declaración de bloque, y una declaración de bloque no puede aparecer en el lado izquierdo de una asignación.
Los paréntesis indican que la siguiente abrazadera no es una declaración de bloque y debe ser interpretada como una expresión, lo que permite completar la asignación.
Una expresión de asignación de desestructuración se evalúa al lado derecho de la expresión (después de la =).
Esto significa que puede usar una expresión de asignación desestructurada donde se espera un valor.
Por ejemplo, considere este ejemplo, que pasa un valor a una función:
let node = {
type: "Identifier",
name: "foo"
},
type = "Literal",
name = 5;
function outputInfo(value) {
console.log(value === node); // true
}
outputInfo({ type, name } = node);
console.log(type); // "Identifier"
console.log(name); // "foo"
The outputInfo() function is called with a destructuring assignment
expression. The expression evaluates to node because that is the value of the
right side of the expression. The assignments to type and name behave normally,
and node is passed to the outputInfo() function.
Not e An error is thrown when the right side of the destructuring assignment expression (the
expression after =) evaluates to null or undefined. This happens because any attempt
to read a property of null or undefined results in a runtime error.
Default Values
When you use a destructuring assignment statement and you specify a local
variable with a property name that doesn’t exist on the object, that local variable
is assigned a value of undefined. For example:
let node = {
type: "Identifier",
name: "foo"
};
let { type, name, value } = node;
console.log(type); // "Identifier"
console.log(name); // "foo"
console.log(value); // undefined
This code defines an additional local variable called value and attempts
to assign it a value. However, no corresponding value property is on the node
object, so the variable is assigned the value of undefined as expected.
You can optionally define a default value to use when a specified property
doesn’t exist. To do so, insert an equal sign (=) after the property name
and specify the default value, like this:
let node = {
type: "Identifier",
name: "foo"
};
let { type, name, value = true } = node;
console.log(type); // "Identifier"
console.log(name); // "foo"
console.log(value); // true
In this example, the variable value is given true as a default value. The
default value is only used if the property is missing on node or has a value of
undefined. Because no node.value property exists, the variable value uses the
default value. This works similarly to the default parameter values for functions,
as discussed in Chapter 3.
Assigning to Different Local Variable Names
Up to this point, each destructuring assignment example has used the
object property name as the local variable name; for example, the value of
node.type was stored in a type variable. That works well when you want to use
the same name, but what if you don’t? ECMAScript 6 has an extended syntax
that allows you to assign to a local variable with a different name, and
that syntax looks like the object literal non-shorthand property initializer
syntax. Here’s an example:
let node = {
type: "Identifier",
name: "foo"
};
let { type: localType, name: localName } = node;
console.log(localType); // "Identifier"
console.log(localName); // "foo"
This code uses destructuring assignments to declare the localType
and localName variables, which contain the values from the node.type and
node.name properties, respectively. The syntax type: localType reads the property
named type and stores its value in the localType variable. This syntax is
effectively the opposite of traditional object literal syntax, where the name
is on the left of the colon and the value is on the right. In this case, the
name is on the right of the colon and the location of the value to read is
on the left.
You can add default values when you’re using a different variable name,
as well. The equal sign and default value are still placed after the local variable
name. For example:
let node = {
type: "Identifier"
};
let { type: localType, name: localName = "bar" } = node;
console.log(localType); // "Identifier"
console.log(localName); // "bar"
Here, the localName variable has a default value of "bar". The variable is
assigned its default value because no node.name property exists.
So far, you’ve learned how to use object destructuring on an object
whose properties are primitive values. You can also use object destructuring
to retrieve values in nested object structures.
Nested Object Destructuring
By using syntax similar to that of object literals, you can navigate into a
nested object structure to retrieve just the information you want. Here’s
an example:
let node = {
type: "Identifier",
name: "foo",
loc: {
start: {
line: 1,
column: 1
},
end: {
line: 1,
column: 4
}
}
};
let { loc: { start }} = node;
console.log(start.line); // 1
console.log(start.column); // 1
The destructuring pattern in this example uses curly braces to indicate
that the pattern should descend into the property named loc on node and
look for the start property. Recall from the previous section that a colon
in a destructuring pattern means the identifier before the colon is giving a
location to inspect, and the right side assigns a value. A curly brace after the
colon indicates that the destination is nested another level into the object.
You can go one step further and use a different name for the local variable
as well:
let node = {
type: "Identifier",
name: "foo",
loc: {
start: {
line: 1,
column: 1
},
end: {
line: 1,
column: 4
}
}
};
// extract node.loc.start
let { loc: { start: localStart }} = node;
console.log(localStart.line); // 1
console.log(localStart.column); // 1
In this version of the code, node.loc.start is stored in a new local variable
called localStart. Destructuring patterns can be nested to an arbitrary
level of depth, and all capabilities will be available at each level.
Object destructuring is very powerful because it provides you with lots
of options, but array destructuring offers some unique capabilities that
allow you to extract information from arrays.
####**Mixed**
Mixed Destructuring
You can use object and array destructuring together to create more complex
expressions. By doing so, you’re able to extract just the pieces of information
you want from any mixture of objects and arrays. Consider the following
example.
let node = {
type: "Identifier",
name: "foo",
loc: {
start: {
line: 1,
column: 1
},
end: {
line: 1,
column: 4
}
},
range: [0, 3]
};
let {
loc: { start },
range: [ startIndex ]
} = node;
console.log(start.line); // 1
console.log(start.column); // 1
console.log(startIndex); // 0
This code extracts node.loc.start and node.range[0] into start and
startIndex, respectively. Keep in mind that loc: and range: in the destructured
pattern are just locations that correspond to properties in the node
object. There is no part of node that cannot be extracted using destructuring
when you use a mix of object and array destructuring. This approach is
particularly useful for pulling values out of JSON configuration structures
without navigating the entire structure.
Destructured Parameters
Destructuring has one more particularly helpful use case and that is when
passing function arguments. When a JavaScript function takes a large number
of optional parameters, one common pattern is to create an options
object whose properties specify the additional parameters, like this:
// properties on options represent additional parameters
function setCookie(name, value, options) {
options = options || {};
let secure = options.secure,
path = options.path,
domain = options.domain,
expires = options.expires;
// code to set the cookie
}
// third argument maps to options
setCookie("type", "js", {
secure: true,
expires: 60000
});
Many JavaScript libraries contain setCookie() functions that look similar
to this one. In this function, the name and value arguments are required,
but secure, path, domain, and expires are not. And because there is no priority
order for the other data, it’s efficient to just have an options object with
named properties rather than list extra named parameters. This approach
works, but now you can’t tell what input the function expects just by looking
at the function definition: you need to read the function body.
Destructured parameters offer an alternative that makes it clearer what
arguments a function expects. A destructured parameter uses an object or
array destructuring pattern in place of a named parameter. To see this in
action, look at this rewritten version of the setCookie() function from the
previous example:
function setCookie(name, value, { secure, path, domain, expires }) {
// code to set the cookie
}
setCookie("type", "js", {
secure: true,
expires: 60000
});
This function behaves similarly to the previous example, but the third
argument now uses destructuring to pull out the necessary data. The parameters
outside the destructured parameter are clearly expected, and it’s also
clear to someone using setCookie() what options are available in terms of
extra arguments. And of course, if the third argument is required, the values
it should contain are crystal clear. The destructured parameters also act like
regular parameters in that they are set to undefined if they’re not passed.
Not e Destructured parameters have all the capabilities of destructuring that you’ve learned
so far in this chapter. You can use default values, mix object and array patterns, and
use variable names that differ from the properties you’re reading from.
Destructured Parameters Are Required
One quirk of using destructured parameters is that, by default, an error is
thrown when they’re not provided in a function call. For instance, the following
call to the setCookie() function from the previous example throws an
error.
// error!
setCookie("type", "js");
The missing third argument evaluates to undefined as expected, causing
an error because destructured parameters are just a shorthand for destructured
declaration. When the setCookie() function is called, the JavaScript
engine actually does this:
function setCookie(name, value, options) {
let { secure, path, domain, expires } = options;
// code to set the cookie
}
Because destructuring throws an error when the right side expression
evaluates to null or undefined, it also throws an error when the third argument
isn’t passed to the setCookie() function.
If you want the destructured parameter to be required, this behavior
isn’t all that troubling. But if you want the destructured parameter to be
optional, you can work around this behavior by providing a default value
for the destructured parameter, like this:
function setCookie(name, value, { secure, path, domain, expires } = {}) {
// empty
}
This example provides a new object as the default value for the third
parameter. Providing a default value for the destructured parameter means
that secure, path, domain, and expires will all be undefined if the third argument
to setCookie() isn’t provided, and no error will be thrown.
Default Values for Destructured Parameters
You can specify destructured default values for destructured parameters
just as you would in destructured assignment. Just add the equal sign after
the parameter and specify the default value. For example:
function setCookie(name, value,
{
secure = false,
path = "/",
domain = "example.com",
expires = new Date(Date.now() + 360000000)
} = {}
) {
// empty
}
Each property in the destructured parameter has a default value in
this code, so you can avoid checking to see if a given property has been
included in order to use the correct value. Also, the entire destructured
parameter has a default value of an empty object, making the parameter
optional. This does make the function declaration look a bit more complicated
than usual, but that’s a small price to pay for ensuring each argument
has a usable value.
Con la desestructuracion de ***array*** y ***object** se pueden convinar para crear expresiones mas complejas y asi extraer la informacion que se desea de esta mezcla de *arrays* y *objects*.
Ejemplo:
```javascript
let node = {
type: "Identifier",
name: "foo",
loc: {
start: {
line: 1,
column: 1
},
end: {
line: 1,
column: 4
}
},
range: [0, 3]
};
let {
loc: { start },
range: [ startIndex ]
} = node;
console.log(start.line); // 1
console.log(start.column); // 1
console.log(startIndex); // 0
```
>Este es un ejemplo útil para extraer valores de las estructuras de configuración de JSON sin navegar por toda la estructura.
### **Modules and Classes:**
***Modulos***: Se destacan por la exportacion e importacion, es una manera de llamar a las clases o métodos, Estos nos ayudan a resolver distintos problemas, entre los cuales tenemos:
- Evitar colisiones de variables por nombres repetidos.
- Separar la lógica de la aplicación en partes específicas y definidas.
- Mantener nuestras variables lejos del scope global.
Aumentar la comprensibilidad y reusabilidad del código.
-***cargadores de modulo:***
- CommonJS: es un proceso ***`síncrono`*** que empieza por un módulo inicial Al cargarse este módulo se cargaran todas sus dependencias.
- AMD: es un proceso que soporta carga ***`asincrona`*** y es mas complicada que ***`commonJs`*** en su sintaxi.
>####-*Exporting:*
>existen dos tipos de exports: ***`named exports`*** (múltiples por módulo) y ***`default exports`*** (solo uno por módulo).
>
>***`named exports`***: son esenciales cuando se desea exportar multiple valores.
>***`default exports`***:cuando se va a pasar un solo valor por metodo
>####-*importacion:*
>
***Classes:***
JavaScript has been a prototypal based language using object prototypes to create object inheritance and code reuse. The new ES6 Class adds a new syntax on top of traditional prototypes.
Something I cannot stress enough is the new Class is syntactic sugar on prototypes. Under the hood ES6 Classes are still using prototypal inheritance.
```javascript
import { Component } from './component'
export default class App extends Main {
showInConsole(bar) {
console.log(bar)
}
```
Similarly to functions, there are two kinds of class definitions, two ways to define a class: class declarations and class expressions.
Also similarly to functions, the identifier of a class expression is only visible within the expression:
```javascript
const MyClass = class Me {
getClassName() {
return Me.name;
}
};
let inst = new MyClass();
console.log(inst.getClassName()); // Me
console.log(Me.name); // ReferenceError: Me is not defined
```
**Syntax Quirks**
> 1. The new syntax gives us a dedicated constructor statement that runs on object creation. Constructors are helpful for any object initialization logic.
> 2. ES5 getters and setters did not have as nice of a syntax that ES6 brings us.
> 3. To achieve private state on objects you would use ES6 symbol and module to create true encapsulation and private state. Private methods can be created using module or traditional closures using an IIFE.
> 4. One detail you may notice is the super() keyword. The super keyword lets us call the parent object that is being inherited. It is good advice to avoid this as this can cause an even tighter coupling between your objects but there are occasions where it is appropriate to use
#### - **This**
The variable this often becomes a headache. Formerly we had to cache it in another variable since it only refers to the context in which we find ourselves.
For example, in the following code if we do not do ***`var that = this`*** within the function ***`document.addEventListener`***, this would reference the function we passed through Callback and we could not call ***` foo ()`***
```javascript
//ES3
var obj = {
foo : function() {...},
bar : function() {
var that = this;
document.addEventListener("click", function(e) {
that.foo();
});
}
}
```
With ECMAScript5 the thing changed a little, and thanks to the bind method we could indicate that this refers to one context and not another.
```javascript
//ES5
var obj = {
foo : function() {...},
bar : function() {
document.addEventListener("click",
function(e) {
this.foo();
}.bind(this));
}
}
```
Now with ES6 and the ***`Arrow => function `*** the thing is even more visual and simple.
```javascript
//ES6
var obj = {
foo : function() {...},
bar : function() {
document.addEventListener("click", (e) => this.foo());
}
}
```
#### - **let y const**
Instead of ***`var`*** we can now declare variables with ***`let`***.
For example:
```javascript
//ES5
(function() {
console.log(x);
// x no está definida aún.
if(true) {
var x = "hola mundo";
}
console.log(x);
// Prints "hello world",
// because "var" causes it to be global
// to the function;
})();
```
```javascript
//ES6
(function() {
if(true) {
let x = "hola mundo";
}
console.log(x);
// Give error, because "x" has been defined inside the "if"
})();
```
With ***`const `*** we can create constants that can only be read and not modified throughout the code.
Let's look at an example:
```javascript
(function() {
const PI;
PI = 3.15;
// ERROR, because a value must be
// assigned in the declaration
})();
(function() {
const PI = 3.15;
PI = 3.14159;
// ERROR again, because it is read-only
})();
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment