Guía de JavaScript Parte 9: Descripción general de los estándares ES7, ES8 y ES9

Hoy, en la novena parte de la traducción del manual de JavaScript, se ofrecerá una descripción general de las características que han aparecido en el idioma gracias a los estándares ES7, ES8 y ES9.

Parte 1: primer programa, características del lenguaje, estándares
Parte 2: estilo de código y estructura del programa
Parte 3: variables, tipos de datos, expresiones, objetos.
Parte 4: características
Parte 5: matrices y bucles
Parte 6: excepciones, punto y coma, literales comodín
Parte 7: modo estricto, esta palabra clave, eventos, módulos, cálculos matemáticos
Parte 8: Descripción general de las características de ES6
Parte 9: Descripción general de los estándares ES7, ES8 y ES9



Estándar ES7


El estándar ES7, que, de acuerdo con la terminología oficial, se llama ES2016, se lanzó en el verano de 2016. Él, en comparación con ES6, traído al lenguaje no es mucho nuevo. En particular, estamos hablando de lo siguiente:

  • Array.prototype.includes() método.
  • Operador de exponenciación.

▍ Método Array.prototype.includes ()


El método Array.prototype.includes() está diseñado para verificar la presencia de un elemento en la matriz. Al encontrar lo deseado en la matriz, devuelve true , no encontrar, false . Antes de ES7, el método indexOf() se usaba para realizar la misma operación, que devuelve, si se encuentra un elemento, el primer índice por el cual se puede encontrar en la matriz. Si indexOf() no encuentra el elemento, devuelve el número -1 .

De acuerdo con las reglas de conversión de tipo JavaScript, el número -1 convierte en true . Como resultado, para verificar los resultados de la operación de indexOf() se debe usar una construcción no particularmente conveniente del siguiente formulario.

 if ([1,2].indexOf(3) === -1) { console.log('Not found') } 

Si en una situación similar, suponiendo que indexOf() , sin encontrar un elemento, devuelve false , use algo como el que se muestra a continuación, el código no funcionará correctamente.

 if (![1,2].indexOf(3)) { // console.log('Not found') } 

En este caso, resulta que la construcción ![1,2].indexOf(3) da false .

Usando el método includes() , tales comparaciones parecen mucho más lógicas.

 if (![1,2].includes(3)) { console.log('Not found') } 

En este caso, la construcción [1,2].includes(3) devuelve false , ¡este valor es un operador ! se convierte en true y la consola recibe un mensaje que indica que no se encontró el elemento en la matriz.

▍ operador de exponenciación


El operador de exponenciación realiza la misma función que el método Math.pow() , pero es más conveniente usarlo que una función de biblioteca, ya que es parte del lenguaje.

 Math.pow(4, 2) == 4 ** 2 //true 

Este operador puede considerarse una adición agradable a JS, que es útil en aplicaciones que realizan ciertos cálculos. Existe un operador similar en otros lenguajes de programación.

Estándar ES8


El estándar ES8 (ES2017) se lanzó en 2017. Él, como ES7, no aportó mucho al idioma. A saber, estamos hablando de las siguientes características:

  • Agregar cadenas a una longitud determinada.
  • Método Object.values() .
  • Método Object.entries() .
  • Método Object.getOwnPropertyDescriptors() .
  • Comas finales en los parámetros de la función.
  • Funciones asincrónicas.
  • Trabajar con memoria compartida y operaciones atómicas.

▍ Agregar líneas a una longitud dada


ES8 introdujo dos nuevos métodos de objeto String : padStart() y padEnd() .

El método padStart() llena la línea actual con otra línea hasta que la línea final alcanza la longitud deseada. El llenado ocurre al comienzo de la línea (izquierda). Aquí se explica cómo usar este método.

 str.padStart(targetLength [, padString]) 

Aquí str es la línea actual, targetLength es la longitud de la línea final (si es menor que la longitud de la línea actual, esta línea se devolverá sin cambios), padString es un parámetro opcional: la línea utilizada para llenar la línea actual. Si no se especifica padString , se utiliza un carácter de espacio para padString línea actual a la longitud especificada.

El método padEnd() es similar a padStart() , pero la línea se rellena a la derecha.

Considere ejemplos de uso de estos métodos.

 const str = 'test'.padStart(10) const str1 = 'test'.padEnd(10,'*') console.log(`'${str}'`) //'      test' console.log(`'${str1}'`) //'test******' 

Aquí, cuando se usa padStart() con solo la longitud deseada de la cadena resultante, se agregaron espacios al comienzo de la cadena original. Al usar padEnd() con la longitud de la línea final y la línea para llenarla, los caracteres * se agregaron al final de la línea original.

▍ Método Object.values ​​()


Este método devuelve una matriz que contiene los valores de las propiedades propias del objeto, es decir, las propiedades que contiene el objeto en sí y no las que son accesibles a través de la cadena de prototipos.

Aquí se explica cómo usarlo.

 const person = { name: 'Fred', age: 87 } const personValues = Object.values(person) console.log(personValues) // ['Fred', 87] 

Este método también se aplica a las matrices.

▍ Método Object.entries ()


Este método devuelve una matriz, cada elemento del cual también es una matriz que contiene, en el formato [key, value] , claves y valores de las propiedades del objeto.

 const person = { name: 'Fred', age: 87 } const personValues = Object.entries(person) console.log(personValues) // [['name', 'Fred'], ['age', 87]] 

Al aplicar este método a las matrices, los índices de los elementos se muestran como claves, y lo que se almacena en la matriz en los índices correspondientes se muestra como valores.

▍ método getOwnPropertyDescriptors ()


Este método devuelve información sobre todas las propiedades del objeto. Los conjuntos de atributos (descriptores) están asociados con las propiedades del objeto. En particular, estamos hablando de los siguientes atributos:

  • value : el valor de la propiedad del objeto.
  • writable : contiene true si la propiedad se puede cambiar.
  • get : contiene una función getter asociada con la propiedad o, si no existe, undefined .
  • set : contiene la función setter de la propiedad o undefined .
  • configurable , si es false , la propiedad no se puede eliminar, sus atributos no se pueden cambiar, excepto el valor.
  • enumerable : si verdadero está contenido en esta propiedad, la es enumerable.

Aquí se explica cómo usar este método.

 Object.getOwnPropertyDescriptors(obj) 

Toma un objeto cuya información de propiedad necesita averiguar y devuelve un objeto que contiene esta información.

 const person = { name: 'Fred', age: 87 } const propDescr = Object.getOwnPropertyDescriptors(person) console.log(propDescr) /* { name:  { value: 'Fred',    writable: true,    enumerable: true,    configurable: true }, age:  { value: 87,    writable: true,    enumerable: true,    configurable: true } } */ 

¿Por qué se necesita este método? El hecho es que le permite crear pequeñas copias de objetos, copiando, además de otras propiedades, captadores y establecedores. Esto no se pudo hacer usando el método Object.assign() , que apareció en el estándar ES6, para copiar objetos.

El siguiente ejemplo tiene un objeto con un setter que muestra, usando console.log() , lo que están tratando de escribir en su propiedad correspondiente.

 const person1 = { set name(newName) {     console.log(newName) } } person1.name = 'x' // x 

Intentemos copiar este objeto usando el método assign() .

 const person2 = {} Object.assign(person2, person1) person2.name = 'x' //     ,    

Como puede ver, este enfoque no funciona. La propiedad de name , que fue la que establece el objeto original, ahora se representa como una propiedad normal.

Ahora Object.defineProperties() el objeto utilizando los métodos Object.defineProperties() (apareció en ES5.1) y Object.getOwnPropertyDescriptors() .

 const person3 = {} Object.defineProperties(person3, Object.getOwnPropertyDescriptors(person1)) person3.name = 'x' //x 

Aquí, el colocador permanece en la copia del objeto.

Cabe señalar que las restricciones específicas de Object.assign() también son características del método Object.create() cuando se utiliza para clonar objetos.

▍Comas de terminación en parámetros de función


Esta característica le permite dejar una coma al final de la lista de parámetros o argumentos, respectivamente, al declarar y al llamar a funciones.

 const doSomething = ( var1, var2, ) => { //... } doSomething( 'test1', 'test2', ) 

Esto mejora la usabilidad de los sistemas de control de versiones. Es decir, estamos hablando del hecho de que al agregar nuevos parámetros a una función, no tiene que cambiar el código existente solo por insertar una coma.

▍Funciones asincrónicas


La construcción async/await ha aparecido en el estándar ES2017, que puede considerarse la innovación más importante de esta versión del lenguaje.

Las funciones asincrónicas son una combinación de promesas y generadores; simplifican las construcciones que anteriormente requerían una gran cantidad de código de plantilla y cadenas de promesas inconvenientes para describir. De hecho, estamos hablando de una abstracción de alto nivel sobre las promesas.

Cuando aparecieron las promesas en el estándar ES2015, fueron diseñadas para resolver problemas existentes con código asincrónico, lo que hicieron. Pero durante los dos años que compartieron los estándares ES2015 y ES2017, quedó claro que las promesas no pueden considerarse la solución final a estos problemas.

En particular, las promesas estaban destinadas a resolver el problema del "infierno de devolución de llamada", pero, al resolver este problema, ellos mismos no mostraron su mejor lado debido a la complejidad del código en el que se utilizan. De hecho, la construcción async/await resuelve el problema de las promesas y mejora la usabilidad del código asíncrono.

Considera un ejemplo.

 function doSomethingAsync() { return new Promise((resolve) => {     setTimeout(() => resolve('I did something'), 3000) }) } async function doSomething() { console.log(await doSomethingAsync()) } console.log('Before') doSomething() console.log('After') 

Este código enviará lo siguiente a la consola.

 Before After I did something 

Como puede ver, después de llamar a doSomething() programa continúa ejecutándose, después de que se muestre Before , After en la consola, y después de que hayan pasado tres segundos, I did something .

Llamada de función asíncrona en serie


Si es necesario, las funciones asincrónicas pueden formar algo así como cadenas de llamadas. Dichos diseños se distinguen por una mejor legibilidad que algo similar, basado únicamente en promesas. Esto se puede ver en el siguiente ejemplo.

 function promiseToDoSomething() { return new Promise((resolve)=>{     setTimeout(() => resolve('I did something'), 10000) }) } async function watchOverSomeoneDoingSomething() { const something = await promiseToDoSomething() return something + ' and I watched' } async function watchOverSomeoneWatchingSomeoneDoingSomething() { const something = await watchOverSomeoneDoingSomething() return something + ' and I watched as well' } watchOverSomeoneWatchingSomeoneDoingSomething().then((res) => { console.log(res) // I did something and I watched and I watched as well }) 

▍ Memoria compartida y operaciones atómicas


Aquí estamos hablando del objeto SharedArrayBuffer , que le permite describir áreas de memoria compartida, y el objeto Atomics , que contiene un conjunto de operaciones atómicas en forma de métodos estáticos. Los detalles sobre las posibilidades que estos objetos le dan al programador se pueden encontrar aquí .

Estándar ES9


ES9 (ES2018) es la última versión del estándar en el momento de la publicación de este material. Estas son sus principales características:

  • Aplicar declaraciones de propagación y descanso a los objetos.
  • Iteradores asincrónicos.
  • Método Promise.prototype.finally() .
  • Mejoras en la expresión regular.

▍ Aplicación de operadores de dispersión y descanso a objetos


Ya hemos hablado sobre el resto y los operadores de propagación que aparecieron en ES6 y se pueden usar para trabajar con matrices. Ambos parecen tres puntos. El operador rest, en el siguiente ejemplo de desestructuración de una matriz, le permite poner sus elementos primero y segundo en las constantes first y second , y todo el resto en los others constantes.

 const numbers = [1, 2, 3, 4, 5] const [first, second, ...others] = numbers console.log(first) //1 console.log(second) //2 console.log(others) //[ 3, 4, 5 ] 

El operador de spread permite pasar matrices a funciones que esperan listas de parámetros regulares.

 const numbers = [1, 2, 3, 4, 5] const sum = (a, b, c, d, e) => a + b + c + d + e const res = sum(...numbers) console.log(res) //15 

Ahora, utilizando el mismo enfoque, puede trabajar con objetos. Aquí hay un ejemplo del uso de la declaración rest en una operación de asignación destructiva.

 const { first, second, ...others } = { first: 1, second: 2, third: 3, fourth: 4, fifth: 5 } console.log(first) //1 console.log(second) //2 console.log(others) //{ third: 3, fourth: 4, fifth: 5 } 

Aquí está la declaración de propagación utilizada al crear un nuevo objeto basado en uno existente. Este ejemplo continúa el anterior.

 const items = { first, second, ...others } console.log(items) //{ first: 1, second: 2, third: 3, fourth: 4, fifth: 5 } 

▍ iteradores asincrónicos


La nueva construcción for-await-of permite llamar a funciones asincrónicas que devuelven promesas en bucles. Tales bucles esperan la resolución de la promesa antes de pasar al siguiente paso. Así es como se ve.

 for await (const line of readLines(filePath)) { console.log(line) } 

Al mismo tiempo, debe tenerse en cuenta que tales bucles deben usarse en funciones asincrónicas, de la misma manera que cuando se trabaja con la construcción async/await .

Method Método Promise.prototype.finally ()


Si la promesa se resuelve con éxito, se llama al siguiente método then() . Si algo sale mal, se llama al método catch() . El método finally() permite ejecutar algo de código independientemente de lo que sucedió antes.

 fetch('file.json') .then(data => data.json()) .catch(error => console.error(error)) .finally(() => console.log('finished')) 

▍ Mejoras de expresión regular


Las expresiones regulares tienen la capacidad de verificar retrospectivamente las cadenas ( ?<= ). Esto le permite buscar ciertas construcciones en las líneas antes de las cuales hay otras construcciones.

La capacidad de preceder las comprobaciones utilizando el constructo ?= Estaba presente en expresiones regulares implementadas en JavaScript antes del estándar ES2018. Dichas verificaciones le permiten saber si otro fragmento sigue a cierto fragmento de una línea.

 const r = /Roger(?= Waters)/ const res1 = r.test('Roger is my dog') const res2 = r.test('Roger is my dog and Roger Waters is a famous musician') console.log(res1) //false console.log(res2) //true 

Construcción ?! realiza la operación opuesta: se encontrará una coincidencia solo si otra línea no sigue la línea dada.

 const r = /Roger(?! Waters)/g const res1 = r.test('Roger is my dog') const res2 = r.test('Roger is my dog and Roger Waters is a famous musician') console.log(res1) //true console.log(res2) //false 

En la verificación retrospectiva, como ya se mencionó, ?<= utiliza la construcción ?<= .

 const r = /(?<=Roger) Waters/ const res1 = r.test('Pink Waters is my dog') const res2 = r.test('Roger is my dog and Roger Waters is a famous musician') console.log(res1) //false console.log(res2) //true 

La operación opuesta a la descrita se puede realizar utilizando la construcción ?<! .

 const r = /(?<!Roger) Waters/ const res1 = r.test('Pink Waters is my dog') const res2 = r.test('Roger is my dog and Roger Waters is a famous musician') console.log(res1) //true console.log(res2) //false 

Secuencias de escape de expresiones regulares Unicode


En las expresiones regulares, puede usar la clase \d que coincide con cualquier dígito, la clase \s que coincide con cualquier carácter de espacio en blanco, la clase \w que coincide con cualquier carácter alfanumérico, etc. La función en cuestión amplía el conjunto de clases que se pueden usar en expresiones regulares, lo que le permite trabajar con secuencias Unicode. Estamos hablando de la clase \p{} y la inversa de la clase \P{} .

En Unicode, cada personaje tiene un conjunto de propiedades. Estas propiedades se indican entre llaves del grupo \p{} . Entonces, por ejemplo, la propiedad Script determina la familia de idiomas a la que pertenece un carácter, la propiedad ASCII , lógica, toma true para los caracteres ASCII, y así sucesivamente. Por ejemplo, descubriremos si algunas líneas contienen solo caracteres ASCII.

 console.log(r.test('abc')) //true console.log(r.test('ABC@')) //true console.log(r.test('ABC')) //false 

La propiedad ASCII_Hex_Digit es true solo para los caracteres que se pueden usar para escribir números hexadecimales.

 const r = /^\p{ASCII_Hex_Digit}+$/u console.log(r.test('0123456789ABCDEF')) //true console.log(r.test('H')) //false 

Hay muchas otras propiedades similares que se utilizan de la misma manera que se describe anteriormente. Entre ellos se encuentran Uppercase , Lowercase , White_Space , Alphabetic , Emoji .

Por ejemplo, a continuación se explica cómo usar la propiedad Script para determinar qué alfabeto se usa en una cadena. Aquí verificamos la cadena para el uso del alfabeto griego.

 const r = /^\p{Script=Greek}+$/u console.log(r.test('ελληνικά')) //true console.log(r.test('hey')) //false 

Los detalles sobre estas propiedades se pueden encontrar aquí .

Grupos nombrados


Los grupos de caracteres capturados en ES2018 pueden recibir nombres. Así es como se ve.

 const re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/ const result = re.exec('2015-01-02') console.log(result) /* [ '2015-01-02', '2015', '01', '02', index: 0, input: '2015-01-02', groups: { year: '2015', month: '01', day: '02' } ] */ 

Sin el uso de grupos con nombre, los mismos datos solo estarían disponibles como elementos de matriz.

 const re = /(\d{4})-(\d{2})-(\d{2})/ const result = re.exec('2015-01-02') console.log(result) /* [ '2015-01-02', '2015', '01', '02', index: 0, input: '2015-01-02', groups: undefined ] */ 

Bandera de Regex


Usar la bandera s da como resultado un personaje . (dot) coincidirá, entre otros, con el carácter de nueva línea. Sin esta bandera, un punto coincide con cualquier carácter, excepto una nueva línea.

 console.log(/hi.welcome/.test('hi\nwelcome')) // false console.log(/hi.welcome/s.test('hi\nwelcome')) // true 

Resumen


Con este material, estamos completando la publicación de las traducciones de este manual de JavaScript. Esperamos que estas publicaciones hayan ayudado a aquellos que no habían trabajado con JavaScript antes a dar sus primeros pasos en la programación en este lenguaje.

Estimados lectores! Si no ha escrito en JS antes y ha dominado este idioma en esta guía, comparta sus impresiones.

Source: https://habr.com/ru/post/es431872/


All Articles