Aprendamos ES2015 | Programar Plus

La siguiente es una publicación invitada de Ryan Christiani. Ryan es profesor en HackerYou y ha estado trabajando en una serie de videos llamada Let’s Learn ES6. Se ofreció a juntar algo de eso en un formato de tutorial, que pensé que era perfecto ya que no hemos cubierto mucho ES2015 aquí en CSS-Tricks.

¿Lo que hay en un nombre?

En junio de 2015, se finalizó la mayor incorporación al lenguaje JavaScript. El nombre oficial es ECMAScript 2015, a veces denominado “ES6”, o ahora más comúnmente conocido como “ES2105”. Es la culminación de años de trabajo y características.

En el futuro, habrá ECMAScript 2016, que probablemente se denominará “ES7” o “ES2016”. El plan es tener lanzamientos anuales incrementales.

La mayoría de los navegadores han comenzado a implementar las funciones de ES2015, pero el soporte varía entre ellos. Puede ver la compatibilidad actual del navegador para esta implementación usando esta tabla.

Herramientas como Babel nos permiten escribir nuevo código ES2015 hoy y realizar una tarea llamada transpilación (muy parecida al preprocesamiento) para convertir el código en una versión anterior de JavaScript que tenga mayor compatibilidad con el navegador. Esto es similar a cómo funciona Sass; inicialmente escribiendo su código en sintaxis Sass, y luego un preprocesador lo compila en CSS estándar.

Descripción general

En este artículo, veremos algunas características que ahora están disponibles para usar como desarrolladores.

Examinaremos nuevas palabras clave como let y const, cómo crear literales de plantilla para facilitar la concatenación, la nueva sintaxis de la función de flecha, el operador de propagación y los parámetros de descanso. Aquí hay una tabla de contenido:

  1. let y const
  2. Literales de plantilla
  3. Funciones de flecha
  4. Operadores de propagación
  5. Parámetros de descanso

¡Estas adiciones pueden ayudar a que escribir JavaScript sea un verdadero placer!

let y const

let y const son dos nuevas palabras clave que ahora están disponibles en ES2015. Se utilizan para declarar variables, sin embargo, hay una característica clave que comparten estas variables que las distingue de var: crean variables de ámbito de bloque.

Cuando usa el var palabra clave para crear una variable, tiene el alcance de la función y es local solo para esa función. Esto significa que está disponible dentro de la función en la que se creó y cualquier función anidada dentro de esa. Pero NO está disponible fuera de allí. Si usaste var para definir una variable fuera de cualquier función, estaría disponible globalmente.

Un problema común con el que nos encontraremos con las variables de ámbito de función es el for círculo.

for (var i = 0; i < 10; i++) {
  console.log(i);
}
console.log(i); // Will print out 10;

Es común declarar una variable dentro de la for bucle con la intención de que esté vinculado a eso for bucle sin embargo, ese no es ese caso. Si ejecuta el código anterior, verá el i La variable está disponible fuera del bucle for.

Si quieres usar let o const primero tendrá que habilitar el modo estricto para su archivo JavaScript. Añadiendo 'use strict' en la parte superior de su documento habilita una variante restringida de JavaScript.

'use strict';

El modo estricto es una forma de optar por una versión de JavaScript que corrige algunos errores en el idioma y los convierte en errores. ¡También prohíbe la sintaxis que probablemente se definirá en el futuro! Por ejemplo, en modo estricto, no puede crear una variable con el nombre de let. Para obtener más información sobre el modo estricto, consulte la página MDN sobre el tema.

(Nota del editor: si estamos usando Babel, entonces no tenemos que preocuparnos por “usar estricto” porque lo agregará automáticamente a nuestro código, pero ciertamente vale la pena saber que sucede).

Un “bloque” en JavaScript es cualquier cosa entre { }. Entonces, cuando hablamos de alcance de bloque, ¡eso significa que cualquier variable definida entre corchetes solo existirá en ese bloque!

var tiene el alcance de la función, por lo que la creación de una variable dentro de un bloque con var también lo hará disponible fuera del bloque.

{
  var user = "Ryan";
}
console.log(user); // Ryan

Cuando define una variable con la let palabra clave, creará una nueva variable solo dentro de la { } o bloque.

{
  let user = "Ryan";
}
console.log(user); // Uncaught ReferenceError: user is not defined

¡Esto define y vincula una variable solo al bloque en el que se encuentra! Si echamos un vistazo a la for ejemplo de bucle de nuevo, y reemplace var con let

for (let i = 0; i < 10; i++) {
  console.log(i);
}
console.log(i); // Uncaught ReferenceError: i is not defined 

Ahora funciona según lo previsto. El const La palabra clave se comporta exactamente de la misma manera, con una excepción. Una vez que se define el valor base, nunca se puede redefinir. Es un valor de solo lectura.

const person = 'Ryan';
person = 'Kristen'; // Uncaught TypeError: Assignment to constant variable.
console.log(person);

El navegador arrojará un error si intenta reasignar un valor a una variable definida con const. Dicho esto, puedes hacer algo como esto.

const person = {
  name: 'Ryan'
};
person.name="Kristen";

console.log(person); // {name: 'Kristen'}

Utilizando const no crea un valor inmutable, el valor almacenado en la variable person sigue siendo un objeto, sin embargo, acabamos de cambiar una propiedad dentro de ella. Si está buscando bloquear un objeto, mire Object.freeze().

Cuándo usar let y cuando usar const

Hay un poco de debate en este momento sobre cuándo usar let vs const. La regla general es que si sabe que el valor no se redefinirá a lo largo de su programa, vaya con const, si necesita un valor que pueda cambiar, vaya con let. Hacerle saber al navegador que una variable será constante a lo largo del programa le permitirá hacer ciertos ajustes, ¡y esto podría aumentar el rendimiento!

Literales de plantilla

En ES2015 hay una nueva forma de definir una cadena y viene con algunos beneficios adicionales. Actualmente, si desea definir una cadena, puede usar '' o "".

let name = "Ryan";
let job = 'Instructor';

Si desea concatenar cadenas, puede usar el + operador.

let name = "Ryan";
let job = "Instructor";
let sentence = name + " works at HackerYou as an " + job;
console.log(sentence); // "Ryan works at HackerYou as an Instructor"

A medida que aumenta la cantidad que necesita concatenar, este patrón se vuelve bastante tedioso y rebelde. Introduzca los literales de la plantilla.

Para crear una cadena literal de plantilla, usamos la comilla invertida ` en lugar de las comillas.

let name = `Ryan`;
let job = `Instructor`;

Se comportan exactamente igual que un literal de cadena normal, pero hay una diferencia. Con un literal de plantilla, la concatenación se vuelve mucho más fácil.

let name = `Ryan`;
let job = `Instructor`;
let sentence = `${name} works at HackerYou as an ${job}`;
console.log(sentence); // "Ryan works at HackerYou as an Instructor"

Observe la ${} sintaxis dentro de la cadena? Este es un marcador de posición de plantilla. Nos permite crear una plantilla de nuestras cadenas, y el navegador reemplazará el ${} expresión con el valor adecuado en tiempo de ejecución. Esto hace que la concatenación de cadenas grandes sea mucho más agradable.

¡Estos nuevos marcadores de posición también te permiten realizar expresiones en el interior!

const price = 9.99;
const shipping = 3.99;

const message = `Your total with shipping will be ${price + shipping}.`;

console.log(message); // Your total with shipping will be 13.98.

Multilínea

Una última cosa a tener en cuenta con los literales de plantilla es cómo pueden manejar cadenas de varias líneas. Con una cadena normal, si quisiera que abarcara más de una línea, tendría que hacer algo como esto.

const multi = "This is a n multiline string";
console.log(multi);

Incluyendo el n o el carácter de nueva línea obligará al texto a pasar a una nueva línea. Si intentó poner el texto en dos líneas, así:

const multi = "This is a 
multiline string";
console.log(multi);

Arrojaría un error Uncaught SyntaxError: Unexpected token ILLEGAL. Sin embargo, con los literales de plantilla PODEMOS hacer exactamente eso y agregar saltos de línea donde queramos.

const multi = `This is a 
multiline string`;
console.log(multi);

¡Esto nos permite organizar nuestro marcado de una manera considerablemente más limpia!

const person = {
  name: 'Ryan',
  job: 'Developer/Instructor'
};

const markup = `
  <div>
    <h2>${person.name}</h2>
    <h3>${person.job}</h3>
  </div>
`;

Funciones de flecha

Las funciones de flecha son una nueva sintaxis para crear funciones en ES2015. Esto no reemplaza el function() {} sintaxis que conocemos y amamos, pero la veremos cada vez más como la sintaxis de la función de referencia.

const add = (a, b) => {
  return a + b;
};

La parte central de la sintaxis es la falta de function palabra clave al definir una nueva función. En cambio tenemos el => o flecha gorda. Puede llamar a la función como lo haría con cualquier otra.

add(2, 3); // 5

En realidad, hay algunas formas de definir la función de flecha. Por ejemplo, si la función simplemente devuelve un valor y no hay nada más en el cuerpo de la función, podemos eliminar el {} y el return palabra clave.

const add = (a, b) => a + b;

El return aquí está implícito, lo que significa que está implícito en lugar de que tengamos que agregar explícitamente return a nuestro bloque. Si la función solo tiene un parámetro, puede dejar el () fuera de la definición de la función.

const add5 = a => a + 5;

Si no hay parámetros para usar en la función, se usan paréntesis vacíos como marcador de posición.

const eight = () => 3 + 5;

O está surgiendo un nuevo patrón en el que la gente utilizará un _ como marcador de posición en lugar del paréntesis vacío.

const eight = _ => 3 + 5;

Funciones de flecha y programación funcional

Debido a que la sintaxis de la función de flecha es muy pequeña y la mayoría de las operaciones en la programación funcional requieren muy pocas operaciones en el cuerpo de la función. ¡Esta sintaxis es una combinación perfecta para este estilo de programación!

// Without Arrow functions
const numbers = [3,4,5,6,7,8];
const doubleNumbers = numbers.map(function(n) {
  return n * 2;
});

// With arrow functions
const numbers = [3,4,5,6,7,8];
const doubleNumbers = numbers.map( n => n * 2 );

¡La sintaxis le permite convertir esta agradable y sencilla operación en una sola línea!

El this palabra clave

Un lugar con el que se debe tener cuidado al trabajar con funciones de flecha es cómo manejan las this palabra clave. Considere un método en un objeto.

const person = {
  firstName: "Ryan",
  sayName: function() {
    return this.firstName;
  }
}
console.log(person.sayName()); // "Ryan"

Dentro de la sayName método, el this La palabra clave está vinculada a la person objeto. Entonces, ejecutar el método producirá Ryan. Con una función de flecha, el this la palabra clave tiene un ámbito léxico. Esto significa que el alcance de la función se limitará según el lugar donde se definió. El valor de this luego se refiere al ámbito principal.

const person = {
  firstName: "Ryan",
  sayName: () => {
    return this.firstName; 
  }
}
console.log(person.sayName()); // undefined

En este ejemplo, si cambiamos el sayName método de una función anónima a una función de flecha que devolverá undefined! El this estará ligado léxicamente, y en este caso será el window objeto, en el que no hay firstName propiedad. ¡Habrá casos en los que quizás desee que ese sea el resultado correcto! Echale un vistazo a éste ejemplo.

const person = {
  firstName: 'Ryan',
  hobbies: ['Robots', 'Games', 'Internet'],
  showHobbies: function() {
    this.hobbies.forEach(function(hobby) {
      console.log(`${this.firstName} likes ${hobby}`);
    });
  }
};
person.showHobbies();

Ejecutar esto producirá Uncaught TypeError: Cannot read property 'firstName' of undefined. El this en la función de devolución de llamada para nuestro .forEach() El método no está vinculado a nada (en modo estricto, en modo no estricto será el window). Pero si cambiamos la devolución de llamada a una función de flecha, podemos usar la función léxica this para obtener el valor que queremos!

const person = {
  firstName: 'Ryan',
  hobbies: ['Robots', 'Games', 'Internet'],
  showHobbies: function() {
    this.hobbies.forEach(hobby => {
      console.log(`${this.firstName} likes ${hobby}`);
    });
  }
};
person.showHobbies();

El this dentro de nuestro forEach estará vinculado a la person ¡objeto!

Operadores de propagación

¡A veces queremos hacer algo con una matriz que no podemos! Por ejemplo, supongamos que tenemos una matriz de números cuyo máximo queremos encontrar. Math.max parece el método correcto para esto.

const numbers = [39, 25, 90, 123];
const max = Math.max(numbers);
console.log(max); // NaN

Math.max es un método que toma una lista de valores separados por comas y devolverá el más alto. Lamentablemente, no podemos pasarle una matriz. Sin embargo, hay una forma de evitar esto, podemos usar un método llamado .apply que toma una matriz y llama a una función como si la hubiéramos pasado como una lista.

const numbers = [39, 25, 90, 123];
const max = Math.max.apply(null, numbers);
console.log(max); // 123

El primer argumento en .apply es el valor que nos gustaría establecer el this valor para cuando llamamos Math.max, en este ejemplo proporcionamos null. El segundo argumento es la matriz que nos gustaría aplicar a la función. Esto podría ser un poco confuso, ¿y si hubiera una manera más fácil de hacer esto?

Ingrese el operador de propagación

En ES2015 existe el operador de propagación. La sintaxis se ve así:

...numbers

¡Lo que hace esta herramienta es extender o dispersar los elementos de la matriz! Los expandirá en su lugar. Podemos cambiar lo anterior .apply llamada al método para que se parezca a esto ahora.

const numbers = [39, 25, 90, 123];
const max = Math.max(...numbers);
console.log(max); // 123

Spread expandirá la matriz en su lugar y pasará los elementos como si fuera una lista separada por comas.

Usando el operador de propagación para concatizar

¡También puede usar el operador de extensión para concatenar matrices juntas! Dado que spread expande matrices, ¡podemos expandir matrices en matrices!

const numbersArray1 = [3, 4, 5, 7, 8];
const numbersArray2 = [9, 6, 10, 11];
const concatArray = [...numbersArray1, ...numbersArray2];
console.log(concatArray); // [3, 4, 5, 7, 8, 9, 6, 10, 11]

Parámetros de descanso

El operador de propagación nos permite pasar una matriz de argumentos a una función. Por otro lado, los parámetros de descanso nos permiten recopilar los parámetros pasados ​​a nuestras funciones. Al igual que el operador de propagación, la sintaxis del parámetro rest también implica la ... al comienzo de un nombre de variable.

Veamos un ejemplo de esto. Imagina que tenemos una función que toma cualquier número de argumentos y devuelve la suma, add(2, 3, 4, 5, 6, 7) volvería 27.

const add = function() {
  const numbers = Array.prototype.slice.call(arguments);
  return numbers.reduce((a,b) => a + b);
};
add(2, 3, 4, 5, 6, 7);

Sin parámetros de descanso, tendríamos que usar el arguments palabra clave y llamar Array.prototype.slice.call(arguments). Que en el mundo hace Array.prototype.slice.call(arguments) ¡¿significar?! arguments es un objeto Array-LIKE, lo que significa que no es una matriz real, sino una colección de argumentos pasados ​​a una función. Sin embargo, si quisiéramos utilizar un método Array como .reduce() sobre arguments, tendríamos que tocar el violín.

JavaScript se construye a partir de un montón de objetos. Todos estos objetos tienen un objeto padre del que heredan sus métodos y propiedades. Lo hacen a través del .prototype propiedad. Las matrices tienen el .slice método que podemos usar para crear una matriz real a partir de nuestro arguments valor. Utilizando .call podemos llamar al .slice método del prototipo con arguments como el contexto para crear una matriz … que es mucho.

¡Ingrese los parámetros de descanso!

const add = function(...numbers) {
  return numbers.reduce((a, b) => a + b);
};
add(2, 3, 4, 5, 6, 7);

¡GUAU! Eso fue mucho más fácil. Los parámetros de descanso crean una matriz real a partir de los argumentos pasados ​​a una función, por lo que podemos usar métodos como .reduce en eso. ¡Esto nos permite la libertad de realizar tareas similares mucho más fácilmente!

Es importante señalar que puede mezclar y combinar con los parámetros de descanso y el operador de propagación. Considere una función que toma un multiplicador como primer argumento y luego multiplica cualquier valor posterior por ese número.

const multi = (multiplier, ...numbers) => {
  return numbers.map(n => n * multiplier);
}

Definimos la función con un parámetro para el multiplicador y usamos parámetros de descanso para recopilar la cantidad de argumentos que se pasen a esta función.

JavaScript avanza

Hay un montón de características en ES2015 que no revisamos aquí, pero esperamos que esto le brinde una buena base de una nueva y útil sintaxis y adiciones al lenguaje. Si desea obtener más información, consulte mi serie de videos Aprendamos ES6 en YouTube, así como letslearnes6.com, donde puede encontrar información sobre un libro que estoy escribiendo sobre ES6.