10 de mayo de 2017
JavaScript ha progresado mucho en los últimos años. Si estás aprendiendo JavaScript en 2017 y no has tocado ES6, te estás perdiendo una forma más fácil de leer y escribir JavaScript.
No te preocupes si aún no eres un maestro en JavaScript. No necesitas ser impresionante en JavaScript para aprovechar los bonos añadidos que te da ES6. En este artículo, quiero compartir con ustedes ocho funciones de ES6 que uso a diario como desarrollador para ayudarlo a comprender la nueva sintaxis.
- Una lista de características de ES6
- Let y const
- Let vs var
- Let vs const
- Funciones de flecha
- Lo esencial de las funciones arrow
- El léxico this
- Parámetros predeterminados
- Desestructurar
- Objetos de desestructuración
- Arrays de desestructuración
- Intercambiar variables con matrices desestructuradas
- Desestructurar matrices y objetos mientras se declaran funciones
- El parámetro rest y el operador de extensión
- El parámetro rest
- El operador de propagación
- Literales de objetos mejorados
- Abreviaturas de valor de propiedad
- Abreviaturas de método
- Nombres de propiedad de objeto calculados
- Literales de plantilla
- Terminando
Una lista de características de ES6
En primer lugar, ES6 es una gran actualización de JavaScript. Aquí hay una gran lista de características si tienes curiosidad por saber qué hay de nuevo, gracias a Luke Hoban:
- Flechas
- Clases
- Mejorada de objetos literales
- Plantilla de cadenas
- Desestructuración
- por Defecto + resto + spread
- Deje + const
- Iteradores + para…de
- Generadores
- Unicode
- Módulos
- Módulo de cargadores
- Mapa + set + weakmap + weakset
- Proxy
- Símbolos
- Subclassable construido-ins
- Promesas
- Matemáticas + número + cadena + matriz + api de objeto
- Binario y octal literales
- Reflejar api
- Cola llamadas
No dejes que esta gran lista de funciones te aleje de ES6. No necesitas saberlo todo de inmediato. Voy a compartir con ustedes ocho de estas características que uso a diario. Lo son:
- Let y const
- Funciones de flecha
- Parámetros predeterminados
- Desestructuración
- Parámetro de reposo y operador de extensión
- Literales de objeto mejorados
- Literales de plantilla
- Promesas
repase las ocho funciones de las siguientes secciones. Por ahora, repasaré las primeras cinco funciones. Añadiré el resto a medida que avance en las próximas semanas.
Por cierto, el soporte del navegador para ES6 es increíble. Casi todo es compatible de forma nativa si codifica para los navegadores más recientes (Edge y las últimas versiones de FF, Chrome y Safari).
No necesita herramientas sofisticadas como Webpack si desea escribir ES6. Si no tiene soporte para el navegador en su caso, siempre puede recurrir a polyfills creados por la comunidad. Solo búscalos en Google:)
Con eso, saltemos a la primera función.
Let y const
En ES5 (el antiguo JavaScript), estamos acostumbrados a declarar variables con la palabra clave var
. En ES6, esta palabra clave var
se puede reemplazar por let
y const
, dos palabras clave poderosas que simplifican el desarrollo.
veamos primero la diferencia entre let
y var
para entender por qué let
y const
son mejores.
Let vs var
Hablemos primero de var
ya que estamos familiarizados con él.
En primer lugar, podemos declarar variables con la palabra clave var
. Una vez declarada, esta variable se puede usar en cualquier lugar del ámbito actual.
var me = 'Zell'console.log(me) // Zell
En el ejemplo anterior, declaré me
como variable global. Esta variable global me
también se puede usar en una función, como esta:
var me = 'Zell'function sayMe () { console.log(me)}sayMe() // Zell
Sin embargo, lo contrario no es cierto. Si declaro una variable en una función, no puedo usarla fuera de la función.
function sayMe() { var me = 'Zell' console.log(me)}sayMe() // Zellconsole.log(me) // Uncaught ReferenceError: me is not defined
Por lo tanto, podemos decir que var
tiene un ámbito de función. Esto significa que cuando se crea una variable con var
en una función, solo existirá dentro de la función.
Si la variable se crea fuera de la función, existirá en el ámbito externo.
var me = 'Zell' // global scopefunction sayMe () { var me = 'Sleepy head' // local scope console.log(me)}sayMe() // Sleepy headconsole.log(me) // Zell
let
, por otro lado, tiene un alcance de bloque. Esto significa que cuando se crea una variable con let
, solo existirá dentro de su bloque.
Pero espera, ¿qué es un bloque?
Un bloque en JavaScript es cualquier cosa dentro de un par de llaves. Los siguientes son ejemplos de bloques.
{ // new scope block}if (true) { // new scope block}while (true) { // new scope block}function () { // new block scope}
La diferencia entre las variables de ámbito de bloque y de ámbito de función es enorme. Cuando utiliza una variable de ámbito de función, puede sobrescribir accidentalmente una variable sin tener la intención de hacerlo. Este es un ejemplo:
var me = 'Zell'if (true) { var me = 'Sleepy head'}console.log(me) // 'Sleepy head'
En este ejemplo, puede ver que me
se convierte en Sleepy head
después de correr a través del bloque if
. Este ejemplo probablemente no le causará ningún problema, ya que probablemente no declarará variables con el mismo nombre.
Pero cualquier persona que trabaje con var
en una situación de bucle for
puede encontrarse con algo extraño debido a la forma en que las variables están definidas. Considere el siguiente código que registra la variable i
cuatro veces, luego registra i
de nuevo con una función setTimeout
.
for (var i = 1; i < 5; i++) { console.log(i) setTimeout(function () { console.log(i) }, 1000)};
¿Qué esperarías que hiciera este código? Esto es lo que realmente sucede
¿Cómo diablos se convirtió i
en 5
durante cuatro veces dentro de la función de tiempo de espera? Bueno, resulta que, debido a que var
tiene un ámbito de función, el valor de i
se convirtió en 4
incluso antes de que se ejecute la función de tiempo de espera.
Para obtener el valor i
correcto dentro de setTimeout
, que se ejecuta más tarde, necesitamos crear otra función, por ejemplo logLater
, para garantizar que el valor i
no se cambie por el bucle for
antes de que setTimeout
se ejecute:
function logLater (i) { setTimeout(function () { console.log(i) })}for (var i = 1; i < 5; i++) { console.log(i) logLater(i)};
(Por cierto, esto se llama cierre).
La buena noticia es que la rareza en el ámbito de funciones como el ejemplo de bucle for que acabo de mostrarte no sucede con let
. El mismo ejemplo de tiempo de espera que hemos escrito anteriormente podría escribirse como este, y funcionará de inmediato sin escribir funciones adicionales:
for (let i = 1; i < 5; i++) { console.log(i) setTimeout(function () { console.log(i) }, 1000)};
Como puede ver, las variables de ámbito de bloques hacen que el desarrollo sea mucho más simple al eliminar las trampas comunes con variables de ámbito de función. Para simplificar la vida, le recomiendo que use let
sobre var
cada vez que declare variables de JavaScript a partir de ahora. (ES6 ya es el nuevo JavaScript already).
Ahora sabemos lo que hace let
, pasemos a la diferencia entre let
y const
.
Let vs const
Como let
, const
también tiene un alcance bloqueado. La diferencia es que const
no se puede reasignar una vez declarado.
const name = 'Zell'name = 'Sleepy head' // TypeError: Assignment to constant variable.let name1 = 'Zell'name1 = 'Sleepy head'console.log(name1) // 'Sleepy head'
Dado que const
no se puede reasignar, son buenos para que las variables no cambien.
Digamos que tengo un botón que inicia un modal en mi sitio web. Sé que sólo habrá un botón, y no cambiaría. En este caso, puedo usar const
.
const modalLauncher = document.querySelector('.jsModalLauncher')
Al declarar variables, siempre prefiero const
sobre let
siempre que sea posible porque recibo la señal adicional de que la variable no se reasignaría. Luego, utilizo let
para todas las demás situaciones.
A continuación, sigamos adelante y hablemos de las funciones de flecha.
Funciones de flecha
Las funciones de flecha se indican con la flecha gorda (=>
) que se ve en todas partes en el código ES6. Es una abreviatura para hacer funciones anónimas. Se pueden usar en cualquier lugar donde se use la palabra clave function
. Por ejemplo:
let array = // ES5 wayvar moreThan20 = array.filter(function (num) { return num > 20})// ES6 waylet moreThan20 = array.filter(num => num > 20)
Las funciones de flecha son bastante geniales. Ayudan a acortar el código, lo que da menos espacio para ocultar errores. También te ayudan a escribir código que es más fácil de entender una vez que te acostumbras a la sintaxis.
Vamos a sumergirnos en lo esencial de las funciones de flecha para que aprendas a reconocerlas y usarlas.
Lo esencial de las funciones arrow
En primer lugar, hablemos de crear funciones. En JavaScript, probablemente esté acostumbrado a crear funciones de esta manera:
function namedFunction() { // Do something}// using the functionnamedFunction()
Hay un segundo método para crear funciones. Puede crear una función anónima y asignarla a una variable. Para crear una función anónima, dejamos su nombre fuera de la declaración de la función.
var namedFunction = function() { // Do something}
Una tercera forma de crear funciones es crearlas directamente como argumento a otra función o método. Este tercer caso de uso es el más común para funciones anónimas. Este es un ejemplo:
// Using an anonymous function in a callbackbutton.addEventListener('click', function() { // Do something})
Dado que las funciones de flecha ES6 son una abreviatura de funciones anónimas, puede sustituir las funciones de flecha en cualquier lugar donde cree una función anónima.
Así es como se ve:
// Normal Functionconst namedFunction = function (arg1, arg2) { /* do your stuff */}// Arrow Functionconst namedFunction2 = (arg1, arg2) => {/* do your stuff */}// Normal function in a callbackbutton.addEventListener('click', function () { // Do something})// Arrow function in a callbackbutton.addEventListener('click', () => { // Do something})
¿Ves la similitud aquí? Básicamente, eliminas la palabra clave function
y la reemplazas por =>
en una ubicación ligeramente diferente.
Pero, ¿cuál es el problema con las funciones de flecha? ¿No estamos sustituyendo function
por =>
?
Bueno, resulta que no solo estamos sustituyendo function
por =>
. La sintaxis de una función de flecha puede cambiar dependiendo de dos factores:
- El número de argumentos requeridos
- Si desea un retorno implícito.
El primer factor es el número de argumentos suministrados a la función arrow. Si solo proporciona un argumento, puede eliminar el paréntesis que rodea a los argumentos. Si no se requieren argumentos, puede sustituir el paréntesis (()
) por un guion bajo (_
).
Todas las siguientes son funciones de flecha válidas.
const zeroArgs = () => {/* do something */}const zeroWithUnderscore = _ => {/* do something */}const oneArg = arg1 => {/* do something */}const oneArgWithParenthesis = (arg1) => {/* do something */}const manyArgs = (arg1, arg2) => {/* do something */}
El segundo factor para las funciones de flecha es si desea un retorno implícito. Las funciones de flecha, de forma predeterminada, crean automáticamente una palabra clave return
si el código solo ocupa una línea y no está encerrado en un bloque.
Por lo tanto, estos dos son equivalentes:
const sum1 = (num1, num2) => num1 + num2const sum2 = (num1, num2) => { return num1 + num2 }
Estos dos factores son la razón por la que puedes escribir código más corto como el moreThan20
que has visto anteriormente:
let array = // ES5 wayvar moreThan20 = array.filter(function (num) { return num > 20})// ES6 waylet moreThan20 = array.filter(num => num > 20)
En resumen, las funciones de flecha son bastante geniales. Ellos toman un poco de tiempo para acostumbrarse, así que darle una oportunidad y se puede usar en todas partes muy pronto.
Pero antes de subirse al carro de las funciones de flecha FTW, quiero informarle sobre otra característica esencial de la función de flecha ES6 que causa mucha confusión: el léxico this
.
El léxico this
this
es una palabra clave única cuyo valor cambia dependiendo de cómo se llame. Cuando se llama fuera de cualquier función, this
tiene como valor predeterminado el objeto Window
en el navegador.
console.log(this) // Window
Cuando se llama a this
en una llamada a función simple, this
se establece en el objeto global. En el caso de los navegadores, this
siempre será Window
.
function hello () { console.log(this)}hello() // Window
JavaScript siempre establece this
en el objeto ventana dentro de una simple llamada a función. Esto explica por qué el valor this
dentro de funciones como setTimeout
es siempre Window
.
Cuando se llama a this
en un método de objeto, this
sería el objeto en sí:
let o = { sayThis: function() { console.log(this) }}o.sayThis() // o
Cuando se llama a la función como constructor, this
se refiere al objeto recién construido.
function Person (age) { this.age = age}let greg = new Person(22)let thomas = new Person(24)console.log(greg) // this.age = 22console.log(thomas) // this.age = 24
Cuando se usa en un receptor de eventos, this
se establece en el elemento que disparó el evento.
let button = document.querySelector('button')button.addEventListener('click', function() { console.log(this) // button})
Como puede ver en las situaciones anteriores, el valor de this
lo establece la función que lo llama. Cada función define su propio valor this
.
En las funciones de flecha gorda, this
nunca se vincula a un nuevo valor, sin importar cómo se llame a la función. this
siempre tendrá el mismo valor this
que su código circundante. (Por cierto, léxico significa relacionado con, que supongo, es cómo el léxico this
obtuvo su nombre).
Bien, eso suena confuso, así que repasemos algunos ejemplos reales.
En primer lugar, nunca desea usar funciones de flecha para declarar métodos de objeto, porque ya no puede hacer referencia al objeto con this
.
let o = { // Don't do this notThis: () => { console.log(this) // Window this.objectThis() // Uncaught TypeError: this.objectThis is not a function }, // Do this objectThis: function () { console.log(this) // o } // Or this, which is a new shorthand objectThis2 () { console.log(this) // o }}
En segundo lugar, es posible que no desee usar las funciones de flecha para crear oyentes de eventos porque this
ya no se vincula al elemento al que adjuntó el oyente de eventos.
Sin embargo, siempre puede obtener el contexto this
correcto con event.currentTarget
. Por eso dije que no.
button.addEventListener('click', function () { console.log(this) // button})button.addEventListener('click', e => { console.log(this) // Window console.log(event.currentTarget) // button})
En tercer lugar, es posible que desee usar el léxico this
en lugares donde el enlace this
cambie sin que usted lo desee. Un ejemplo es la función de tiempo de espera, por lo que nunca tendrá que lidiar con las tonterías this
, that
o self
.
let o = { // Old way oldDoSthAfterThree: function () { let that = this setTimeout(function () { console.log(this) // Window console.log(that) // o }) }, // Arrow function way doSthAfterThree: function () { setTimeout(() => { console.log(this) // o }, 3000) }}
Este caso de uso es particularmente útil si necesita agregar o eliminar una clase después de que haya transcurrido algún tiempo:
let o = { button: document.querySelector('button') endAnimation: function () { this.button.classList.add('is-closing') setTimeout(() => { this.button.classList.remove('is-closing') this.button.classList.remove('is-open') }, 3000) }}
Finalmente, siéntase libre de usar la función flecha gorda en cualquier otro lugar para ayudar a que su código sea más limpio y corto, como el ejemplo moreThan20
que tuvimos arriba:
let array = let moreThan20 = array.filter(num => num > 20)
Sigamos adelante.
Parámetros predeterminados
Parámetros predeterminados en ES6 well bueno, nos da una forma de especificar parámetros predeterminados cuando definimos funciones. Veamos un ejemplo y verás lo útil que es.
digamos que estamos creando una función que anuncia el nombre de un jugador de un equipo. Si escribes esta función en ES5, será similar a lo siguiente:
function announcePlayer (firstName, lastName, teamName) { console.log(firstName + ' ' + lastName + ', ' + teamName)}announcePlayer('Stephen', 'Curry', 'Golden State Warriors')// Stephen Curry, Golden State Warriors
A primera vista, este código se ve bien. Pero, ¿y si tuviéramos que anunciar a un jugador que no está afiliado a ningún equipo?
El código actual falla vergonzosamente si dejamos teamName
fuera:
announcePlayer('Zell', 'Liew')// Zell Liew, undefined
Estoy bastante seguro de que undefined no es un equipo 😉
Si el jugador no está afiliado, anunciar Zell Liew, unaffiliated
tendría más sentido que Zell Liew, undefined
. No estás de acuerdo?
Para obtener announcePlayer
para anunciar Zell Liew, unaffiliated
, una forma es pasar la cadena unaffiliated
como el teamName
:
announcePlayer('Zell', 'Liew', 'unaffiliated')// Zell Liew, unaffiliated
Aunque esto funciona, podemos hacerlo mejor refactorizando unaffiliated
en announcePlayer
comprobando si teamName
está definido.
En la versión ES5, puede refactorizar el código a algo como esto:
function announcePlayer (firstName, lastName, teamName) { if (!teamName) { teamName = 'unaffiliated' } console.log(firstName + ' ' + lastName + ', ' + teamName)}announcePlayer('Zell', 'Liew')// Zell Liew, unaffiliatedannouncePlayer('Stephen', 'Curry', 'Golden State Warriors')// Stephen Curry, Golden State Warriors
O, si eres más inteligente con los operadores ternarios, podrías haber elegido una versión más tersa:
function announcePlayer (firstName, lastName, teamName) { var team = teamName ? teamName : 'unaffiliated' console.log(firstName + ' ' + lastName + ', ' + team)}
En ES6, con parámetros predeterminados, podemos agregar un signo igual (=
) cada vez que definamos un parámetro. Si lo hacemos, ES6 automáticamente establece por defecto ese valor cuando el parámetro no está definido.
Por lo tanto, en este código a continuación, cuando teamName
no está definido, el valor predeterminado es unaffiliated
:
const announcePlayer = (firstName, lastName, teamName = 'unaffiliated') => { console.log(firstName + ' ' + lastName + ', ' + teamName)}announcePlayer('Zell', 'Liew')// Zell Liew, unaffiliatedannouncePlayer('Stephen', 'Curry', 'Golden State Warriors')// Stephen Curry, Golden State Warriors
Es genial, ¿no? 🙂
Una cosa más. Si desea invocar el valor predeterminado, puede pasar undefined
manualmente. Este paso manual de undefined
ayuda cuando el parámetro predeterminado no es el último argumento de una función.
announcePlayer('Zell', 'Liew', undefined)// Zell Liew, unaffiliated
Eso es todo lo que necesita saber sobre los parámetros predeterminados. Es simple y muy útil 🙂
Desestructurar
Desestructurar es una forma conveniente de obtener valores de matrices y objetos. Hay diferencias menores entre la matriz de desestructuración y los objetos, así que hablemos de ellos por separado.
Objetos de desestructuración
Supongamos que tiene el siguiente objeto:
const Zell = { firstName: 'Zell', lastName: 'Liew'}
Para obtener firstName
y lastName
de Zell
, tenía que crear dos variables, luego asignar cada variable a un valor, como este:
let firstName = Zell.firstName // Zelllet lastName = Zell.lastName // Liew
Con la desestructuración, puede crear y asignar estas variables con una sola línea de código. Así es como se desestructuran los objetos:
let { firstName, lastName } = Zellconsole.log(firstName) // Zellconsole.log(lastName) // Liew
¿Ves lo que pasó aquí? Al agregar corchetes ({}
) al declarar variables, le estamos diciendo a JavaScript que cree las variables antes mencionadas, luego asigne Zell.firstName
a firstName
y Zell.lastName
a lastName
respectivamente.
Esto es lo que pasa bajo el capó:
// What you writelet { firstName, lastName } = Zell// ES6 does this automaticallylet firstName = Zell.firstNamelet lastName = Zell.lastName
Ahora, si ya se usa un nombre de variable, no podemos declarar la variable de nuevo (especialmente si usa let
o const
).
Lo siguiente no funciona:
let name = 'Zell Liew'let course = { name: 'JS Fundamentals for Frontend Developers' // ... other properties}let { name } = course // Uncaught SyntaxError: Identifier 'name' has already been declared
Si se encuentra con situaciones como las anteriores, puede cambiar el nombre de las variables mientras se desestructuran con dos puntos (:
).
En este ejemplo a continuación, estoy creando una variable courseName
y asignándole course.name
.
let { name: courseName } = courseconsole.log(courseName) // JS Fundamentals for Frontend Developers// What ES6 does under the hood:let courseName = course.name
Una cosa más.
No se preocupe si intenta desestructurar una variable que no está contenida en un objeto. Simplemente devolverá undefined
.
let course = { name: 'JS Fundamentals for Frontend Developers'}let { package } = courseconsole.log(package) // undefined
Pero espera, eso no es todo. ¿Recuerda los parámetros predeterminados?
También puede escribir parámetros predeterminados para sus variables desestructuradas. La sintaxis es la misma que cuando se definen funciones.
let course = { name: 'JS Fundamentals for Frontend Developers'}let { package = 'full course' } = courseconsole.log(package) // full course
Incluso puede cambiar el nombre de las variables mientras proporciona los valores predeterminados. Solo combina los dos. Se verá un poco raro al principio, pero te acostumbrarás si lo usas a menudo:
let course = { name: 'JS Fundamentals for Frontend Developers'}let { package: packageName = 'full course' } = courseconsole.log(packageName) // full course
Eso es todo para desestructurar objetos. Sigamos adelante y hablemos de matrices de desestructuración 😄
Arrays de desestructuración
Los arrays de desestructuración y los objetos de desestructuración son similares. Usamos corchetes cuadrados () en lugar de corchetes rizados (
{}
).
Cuando se desestructura una matriz,
- La primera variable es el primer elemento de la matriz.
- Su segunda variable es el segundo elemento de la matriz.
- y así sucesivamente…
let = console.log(one) // 1console.log(two) // 2
Es posible desestructurar tantas variables que exceda el número de elementos de la matriz dada. Cuando esto sucede, la variable extra desestructurada será undefined
.
let = console.log(one) // 1console.log(two) // 2console.log(three) // undefined
Al desestructurar matrices, a menudo desestructuramos solo las variables que necesitamos. Si necesita el resto de la matriz, puede usar el operador rest (...
), de esta manera:
let scores = let = scoresconsole.log(first) // 98console.log(second) // 95console.log(third) // 93console.log(rest) //
Hablaremos más sobre los operadores rest en la siguiente sección. Pero por ahora, hablemos de una habilidad única que obtienes con matrices desestructuradas: variables de intercambio.
Intercambiar variables con matrices desestructuradas
Supongamos que tiene dos variables, a
y b
.
let a = 2let b = 3
Quería intercambiar estas variables. Así que a = 3
y b = 2
. En ES5, debe usar una tercera variable temporal para completar el intercambio:
let a = 2let b = 3let temp// swappingtemp = a // temp is now 2a = b // a is now 3b = temp // b is now 2
Aunque esto funciona, la lógica puede ser borrosa y confusa, especialmente con la introducción de una tercera variable.
Ahora vea cómo lo hará de la manera ES6 con matrices desestructuradas:
let a = 2let b = 3; // semicolon required because next line begins with a square bracket// Swapping with destructured arrays = console.log(a) // 3console.log(b) // 2
💥💥💥. ¡Mucho más simple en comparación con el método anterior de intercambiar variables! 🙂
A continuación, hablemos de la desestructuración de matrices y objetos en una función.
Desestructurar matrices y objetos mientras se declaran funciones
Lo mejor de la desestructuración es que puede usarlos en cualquier lugar. Literalmente. Incluso puede desestructurar objetos y matrices en funciones.
Digamos que tenemos una función que toma una matriz de puntuaciones y devuelve un objeto con las tres puntuaciones principales. Esta función es similar a lo que hemos hecho al desestructurar matrices.
// Note: You don't need arrow functions to use any other ES6 featuresfunction topThree (scores) { let = scores return { first: first, second: second, third: third }}
Una forma alternativa de escribir esta función es desestructurar scores
mientras se declara la función. En este caso, hay una línea de código menos que escribir. Al mismo tiempo, sabemos que estamos tomando una matriz.
function topThree () { return { first: first, second: second, third: third }}
Súper genial, ¿no? 😄.
Ahora, aquí tienes un pequeño cuestionario rápido para ti. Dado que podemos combinar parámetros predeterminados y desestructuración al declarar funciones, ¿qué dice lo siguiente?
function sayMyName ({ firstName = 'Zell', lastName = 'Liew'} = {}) { console.log(firstName + ' ' + lastName)}
Esto es complicado. Estamos combinando algunas características.
en Primer lugar, podemos ver que esta función toma un argumento, un objeto. Este objeto es opcional y el valor predeterminado es {}
cuando no está definido.
En segundo lugar, intentamos desestructurar variables firstName
y lastName
del objeto dado. Si se encuentran estas propiedades, utilícelas.
Finalmente, si firstName
o lastName
no está definido en el objeto dado, lo establecemos en Zell
y Liew
respectivamente.
Por lo tanto, esta función produce los siguientes resultados:
sayMyName() // Zell LiewsayMyName({firstName: 'Zell'}) // Zell LiewsayMyName({firstName: 'Vincy', lastName: 'Zhang'}) // Vincy Zhang
Es genial combinar la desestructuración y los parámetros predeterminados en una declaración de función, ¿eh? 😄. Me encanta esto.
A continuación, echemos un vistazo a rest and spread.
El parámetro rest y el operador de extensión
El parámetro rest y el operador de extensión tienen el mismo aspecto. Ambos se significan con tres puntos (...
).
Lo que hacen es diferente dependiendo de para qué se usan. Por eso se nombran de manera diferente. Por lo tanto, echemos un vistazo al parámetro rest y al operador de propagación por separado.
El parámetro rest
Traducido libremente, el parámetro rest significa tomar el resto de las cosas y empaquetarlas en una matriz. Convierte una lista de argumentos separados por comas en una matriz.
Echemos un vistazo al parámetro rest en acción. Imagine que tenemos una función, add
, que resume sus argumentos:
sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) // 55
En ES5, dependíamos de la variable arguments
cuando teníamos que lidiar con una función que recibía un número desconocido de variables. Esta variable arguments
es una matriz Symbol
.
function sum () { console.log(arguments)}sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
Una forma de calcular esta suma de argumentos es convertirla en una Matriz con Array.prototype.slice.call(arguments)
, luego, recorre cada número con un método de matriz como forEach
o reduce
.
Estoy seguro de que puedes hacer forEach
por tu cuenta, así que aquí está el ejemplo reduce
:
// ES5 wayfunction sum () { let argsArray = Array.prototype.slice.call(arguments) return argsArray.reduce(function(sum, current) { return sum + current }, 0)}
Con el parámetro rest ES6, podríamos empaquetar todos los argumentos separados por comas directamente en una matriz.
// ES6 wayconst sum = (...args) => args.reduce((sum, current) => sum + current, 0)// ES6 way if we didn't shortcut it with so many arrow functionsfunction sum (...args) { return args.reduce((sum, current) => sum + current, 0)}
Mucho más limpio? 🙂.
Ahora, encontramos brevemente el parámetro rest anteriormente en la sección de desestructuración. Allí, tratamos de desestructurar una serie de puntuaciones en las tres mejores puntuaciones:
let scores = let = scoresconsole.log(first) // 98console.log(second) // 95console.log(third) // 93
Si quisiéramos el resto de las partituras, podríamos hacerlo empaquetando el resto de las partituras en una matriz con el parámetro rest.
let scores = let = scoresconsole.log(restOfScores) //
Si alguna vez está confundido, recuerde esto: el parámetro rest empaqueta todo en una matriz. Aparece en parámetros de función y durante la desestructuración de matrices.
A continuación, pasemos a la extensión.
El operador de propagación
El operador de propagación se comporta de manera opuesta en comparación con el parámetro rest. Dicho libremente, toma un array y lo distribuye (como jam) en una lista de argumentos separados por comas.
let array = // These two are exactly the sameconsole.log(...array) // one two threeconsole.log('one', 'two', 'three') // one two three
El operador de propagación se utiliza a menudo para ayudar a concatenar matrices de una manera que sea más fácil de leer y entender.
Digamos, por ejemplo, que desea concatenar los siguientes arrays:
let array1 = let array2 = let array3 =
La forma ES5 de concatenar estos dos arrays es usar el método Array.concat
. Puede encadenar múltiples Array.concat
para concatenar cualquier número de matrices, como esta:
// ES5 waylet combinedArray = array1.concat(array2).concat(array3)console.log(combinedArray) //
Con el operador de propagación ES6, puede distribuir las matrices en una nueva matriz, como esta, que es un poco más fácil de leer una vez que se acostumbre a ella:
// ES6 waylet combinedArray = console.log(combinedArray) //
El operador de propagación también se puede usar para eliminar un elemento de una matriz sin mutar la matriz. Este método se usa comúnmente en Redux. Le recomiendo encarecidamente que vea este video de Dan Abramov si está interesado en ver cómo funciona.
Eso es todo para spread:)
Literales de objetos mejorados
Los objetos deberían ser algo familiar para ti ya que estás escribiendo JavaScript. En caso de que no sepas de ellos, se ven algo como esto:
const anObject = { property1: 'value1', property2: 'value2', property3: 'value3',}
Literales de objetos mejorados ES6 trae tres mejoras dulces a los objetos que conoces y amas. Lo son:
- Abreviaturas de valor de propiedad
- Abreviaturas de método
- La capacidad de usar nombres de propiedad computados
Veamos cada una de ellas. Prometo que esto será rápido:)
Abreviaturas de valor de propiedad
¿Ha notado que a veces asigna una variable que tiene el mismo nombre que una propiedad de objeto? Ya sabes, algo como esto:
const fullName = 'Zell Liew'const Zell = { fullName: fullName}
Bueno, ¿no te gustaría escribir esto de una manera más corta, ya que la propiedad (fullName
) y el valor (fullName
)?
(Oh, mocoso mimado)).
Aquí están las buenas noticias. ¡Puedes! 🙂
ES6 mejora los objetos con abreviaturas de valor de propiedad. Esto significa que solo puede escribir la variable si el nombre de su variable coincide con el nombre de su propiedad. ES6 se encarga del resto.
Así es como se ve:
const fullName = 'Zell Liew'// ES6 wayconst Zell = { fullName}// Underneath the hood, ES6 does this:const Zell = { fullName: fullName}
Bastante limpio, ¿eh? Ahora, tenemos menos palabras que escribir, y todos nos vamos a casa felices.
Mientras bailo, por favor, sigue adelante y pasa a más taquigrafía. Me reuniré contigo en breve.
Abreviaturas de método
Los métodos son funciones asociadas a una propiedad. Se nombran especialmente porque son funciones:)
Este es un ejemplo de método:
const anObject = { aMethod: function () { console.log("I'm a method!~~")}}
Con ES6, podemos escribir métodos con una taquigrafía. Podemos eliminar : function
de una declaración de método y funcionará como antes:
const anObject = { // ES6 way aShorthandMethod (arg1, arg2) {}, // ES5 way aLonghandMethod: function (arg1, arg2) {},}
Con esta actualización, los objetos ya obtienen un método abreviado, por lo que no utilice funciones de flecha cuando defina objetos. Romperá el contexto this
(consulte funciones de flecha si no recuerda por qué).
const dontDoThis = { // Noooo. Don't do this arrowFunction: () => {}}
Eso es todo con las abreviaturas de método de objeto. Pasemos a la actualización final que obtenemos para los objetos.
Nombres de propiedad de objeto calculados
A veces se necesita un nombre de propiedad dinámico al crear objetos. En la antigua forma de JavaScript, tendría que crear el objeto, luego asignar su propiedad a in, de esta manera:
// ES5const newPropertyName = 'smile'// Create an object firstconst anObject = { aProperty: 'a value' }// Then assign the propertyanObject = ':D'// Adding a slightly different property and assigning itanObject = 'XD'// Result// {// aProperty: 'a value',// 'bigger smile': 'XD'// smile: ':D',// }
En ES6, ya no necesita hacer esta forma indirecta. Puede asignar nombres de propiedad dinámicos directamente al crear su objeto. La clave es encerrar la propiedad dinámica entre corchetes:
const newPropertyName = 'smile'// ES6 way.const anObject = { aProperty: 'a value', // Dynamic property names! : ':D', : 'XD',}// Result// {// aProperty: 'a value',// 'bigger smile': 'XD'// smile: ':D',// }
¡Schweeet! ¿No lo es? 🙂
Y eso es todo para los literales de objetos mejorados. ¿No dije que sería rápido? 🙂
Pasemos a otra característica impresionante que me encanta: los literales de plantilla.
Literales de plantilla
Manejar cadenas en JavaScript es una experiencia extremadamente torpe. Lo ha experimentado usted mismo cuando creamos la función announcePlayer
previamente en los parámetros predeterminados. Allí, creamos espacios con cuerdas vacías y los unimos con ventajas:
function announcePlayer (firstName, lastName, teamName) { console.log(firstName + ' ' + lastName + ', ' + teamName)}
En ES6, este problema desaparece gracias a los literales de plantilla. (En la especificación, anteriormente se llamaban cadenas de plantilla).
Para crear un literal de plantilla en ES6, debe incluir cadenas con barras de retroceso (`
). Dentro de los backsticks, obtiene acceso a un marcador de posición especial (${}
) donde puede usar JavaScript normalmente.
Así es como se ve en acción:
const firstName = 'Zell'const lastName = 'Liew'const teamName = 'unaffiliated'const theString = `${firstName} ${lastName}, ${teamName}`console.log(theString)// Zell Liew, unaffiliated
¿Ves eso? Podemos agrupar todo con plantillas literales! Dentro de los literales de plantilla, es el inglés normal. Casi como si estuviéramos usando un motor de plantillas:)
La mejor parte de los literales de plantillas es que puedes crear cadenas de varias líneas fácilmente. Esto funciona fuera de la caja:
const multi = `One upon a time,In a land far far away,there lived a witich,who could change night into day`
Un buen truco es usar estas cadenas para crear elementos HTML en JavaScript si los necesita. (Nota: Esta puede no ser la mejor manera de crear elementos HTML, pero aún así es mucho mejor que crearlos uno por uno!).
const container = document.createElement('div')const aListOfItems = `<ul> <li>Point number one</li> <li>Point number two</li> <li>Point number three</li> <li>Point number four</li> </ul>`container.innerHTML = aListOfItemsdocument.body.append(container)
Vea el Lápiz Usando cadenas de varias líneas para crear elementos HTML más complicados de Zell Liew (@zellwk) en CodePen.
Otra característica de los literales de plantilla se llama etiquetas. Las etiquetas son funciones que le permiten manipular el literal de la plantilla, si desea sustituir cualquier cadena.
Así es como se ve:
const animal = 'lamb'// This a tagconst tagFunction = () => { // Do something here}// This tagFunction allows you to manipulate the template literal.const string = tagFunction `Mary had a little ${animal}`
Para ser honesto, a pesar de que las etiquetas de plantilla se ven geniales, todavía no he tenido un caso de uso para ellas. Si desea obtener más información sobre las etiquetas de plantilla, le sugiero que lea esta referencia en MDN.
Eso es todo para los literales de plantilla.
Terminando
Woo! Esas son casi todas las increíbles funciones de ES6 que uso regularmente. ES6 es impresionante. Definitivamente vale la pena tomarse un poco de su tiempo y aprender sobre ellos, para que pueda entender lo que todos los demás escriben.