EcmaScript 10 - JavaScript de este año (ES2019)

La estandarización de JS ha cambiado a un ciclo de actualización de un año, y el comienzo del año es un buen momento para descubrir qué nos espera en el aniversario: ¡la décima edición de EcmaScript!


ES 9 es la versión actual de la especificación .


ES 10 todavía es un borrador .


Hasta la fecha, la Etapa 4 # tiene solo algunas sugerencias.


Y en la Etapa 3 # - ¡una docena entera!


De estos, en mi opinión, los más interesantes son los campos privados de clases # , gramática shebang para scripts # , números de precisión arbitraria # , acceso al contexto global # e importaciones dinámicas # .



KDPV: Imán amarillo con la inscripción "JS ES10" en la pantalla del monitor - de kasper.green & elfafeya.art
Foto por: kasper.green; Imán amarillo: elfafeya.art & kasper.green


Contenido


Cinco etapas #


Etapa 4 - Final #


catch : el argumento se ha convertido en opcional # ;


Symbol().description : acceso a la descripción del símbolo # ;


' EcmaScript' : compatibilidad mejorada con el formato JSON # ;


.toString() - método prototipo actualizado # .


Object.fromEntries() : creación de un objeto a partir de una matriz de pares: clave \ valor # ;


.flat() y .flatMap() son métodos prototipo # array .




Etapa 3 - Prelanzamiento #


# : todo es privado en las clases, a través de octotorp # ;


#!/usr/bin/env node - gramática shebang para scripts # ;


BigInt() : una nueva primitiva para números de precisión arbitrarios # ;


globalThis : una nueva forma de acceder al contexto global # ;


import(dynamic) : importación dinámica # ;


import.meta : metainformación sobre el módulo cargado # ;


JSON.stringify() : corrección del método # ;


RegExp - características en desuso # ;


.trimStart() y .trimEnd() - métodos de cadena prototipo # ;


.matchAll() - .match() con la bandera global # ;


Resultados #




Cinco etapas


Etapa 0Strawman Basting Una idea que se puede implementar a través del complemento Babel .


Etapa 1Propuesta Propuesta Verificación de la viabilidad de la idea.


Etapa 2Borrador Borrador Inicio del desarrollo de la especificación.


Etapa 3Candidato Candidate Preview Specification.;


Etapa 4 ֍ Finalizado Se completa la versión final de la especificación para este año.




Solo consideraremos la Etapa 4 , el estándar de facto.


Y la Etapa 3 , que está a punto de formar parte de ella.





֍ Etapa 4


Estos cambios ya son estándar.


Argumento opcional para catch


https://github.com/tc39/proposal-optional-catch-binding


Antes de ES 10, el catch requería un argumento requerido para recopilar información de error, incluso si no se usaba:


 function isValidJSON(text) { try { JSON.parse(text); return true; } catch(unusedVariable) { //    return false; } } 


Edge aún no se ha actualizado a ES 10, y se espera que se bloquee con un error.


Comenzando con la edición ES 10, los paréntesis pueden omitirse y la catch se convertirá en dos gotas de agua como try .



Mi Chrome ya se ha actualizado a ES 10 y, en algunos lugares, a la Etapa 3 . Otras capturas de pantalla serán de Chrome


código fuente
 function isValidJSON(text) { try { JSON.parse(text); return true; } catch { //   return false; } } 



Acceda a descripciones de enlaces simbólicos


https://tc39.imtqy.com/proposal-Symbol-description/


Se puede obtener indirectamente una descripción de enlace simbólico utilizando el método toString ():


 const symbol_link = Symbol("Symbol description") String(symbol_link) // "Symbol(Symbol description)" 

Comenzando con ES 10, los caracteres tienen una propiedad de descripción que es de solo lectura. Le permite obtener una descripción del símbolo sin ningún baile con una pandereta:


 symbol_link.description // "Symbol description" 

Si no se especifica la descripción, volverá - undefined :


 const without_description_symbol_link = Symbol() without_description_symbol_link.description // undefined const empty_description_symbol_link = Symbol('') empty_description_symbol_link.description // "" 



Cuerdas EcmaScript compatibles con JSON


https://github.com/tc39/proposal-json-superset


EcmaScript, antes de su décima edición, afirma que JSON es un subconjunto de JSON.parse , pero esto no es cierto.


Las líneas JSON pueden contener separadores de línea sin blindaje U+2028 SEPARADOR DE LÍNEA y párrafos U+2029 SEPARADOR DE PÁRRAFO .


ECMAScript se alinea hasta la décima versión - no.


Si llama a eval() en Edge con la cadena "\u2029" ,
se comporta como si hiciéramos un salto de línea, justo en el medio del código:




Con las líneas ES 10, todo está bien:





Refinamiento del método prototipo .toString()


http://tc39.imtqy.com/Function-prototype-toString-revision/


Cambiar objetivos
  • eliminar requisito incompatible hacia atrás:

Si la implementación no puede crear una cadena de código fuente que cumpla con estos criterios, debe devolver una cadena para la cual eval arrojará una excepción con un error de sintaxis.

  • aclarar un requisito de "funcionalmente equivalente";


  • estandarizar la representación de cadena de funciones incorporadas y objetos host;


  • aclarar los requisitos de presentación basados ​​en las "características reales" de un objeto;


  • asegúrese de que el análisis de la cadena contenga el mismo cuerpo de función y la misma lista de parámetros que el original;


  • para las funciones definidas usando el código ECMAScript, toString debería devolver un fragmento del texto fuente desde el comienzo del primer token hasta el final del último token correspondiente a la construcción gramatical correspondiente;


  • para objetos funcionales integrados, toString no debe devolver nada más que una función nativa;


  • para los objetos llamados que no fueron definidos usando el código ECMAScript, toString debe devolver una función Native;


  • para funciones creadas dinámicamente (constructores de funciones o generadores) toString debe sintetizar el texto fuente;


  • para todos los demás objetos, toString debería lanzar una excepción TypeError.



 //   function () { console.log('My Function!'); }.toString(); // function () { console.log('My Function!'); } //     Number.parseInt.toString(); // function parseInt() { [native code] } //     function () { }.bind(0).toString(); // function () { [native code] } //     Symbol.toString(); // function Symbol() { [native code] } //     Function().toString(); // function anonymous() {} //    - function* () { }.toString(); // function* () { } // .call   ,   ,  Function.prototype.toString.call({}); // Function.prototype.toString requires that 'this' be a Function" 



Crear un objeto usando el método Object.fromEntries()


https://github.com/tc39/proposal-object-from-entries


trabaja en cromo


Análogo de _.fromPairs de lodash :


 Object.fromEntries([['key_1', 1], ['key_2', 2]]) // {key_1: 1; key_2: 2} 



Matrices unidimensionales con .flat() y .flatMap()


https://github.com/tc39/proposal-flatMap


trabaja en cromo


La matriz adquirió los prototipos .flat() y .flatMap() , que generalmente son similares a las implementaciones de lodash , pero aún tienen algunas diferencias. Argumento opcional: establece la profundidad máxima de recorrido del árbol:


 const deep_deep_array = [ '≥0 —  ', [ '≥1 —  ', [ '≥2 —  ', [ '≥3 —  ', [ '≥4 —  ' ] ] ] ] ] // 0 —     deep_deep_array.flat(0) //  ["≥0 —  ", Array(2)] // 1 —    deep_deep_array.flat() //  [" ", " ", Array(2)] deep_deep_array.flat(2) //  [" ", " ", " ", Array(2)] deep_deep_array.flat(100500) // [" ", " ", " ", " ", " "] 

.flatMap() equivalente a llamar consecutivamente .map().flat() . La función de devolución de llamada pasada al método debe devolver una matriz que pasará a formar parte de una matriz plana común:


 ['Hello', 'World'].flatMap(word => [...word]) // ["H", "e", "l", "l", "o", "W", "o", "r", "l", "d"] 

Usando solo .flat() y .map() , el ejemplo se puede reescribir así:


  ['Hello', 'World'].map(word => [...word]).flat() // ["H", "e", "l", "l", "o", "W", "o", "r", "l", "d"] 

También tenga en cuenta que .flatMap() , a diferencia de .flat() no tiene configuraciones de profundidad de rastreo. Entonces solo el primer nivel estará pegado.







֍ Etapa 3


Propuestas que han surgido del estado de borrador, pero que aún no han ingresado a la versión final de la norma.


Privado \ estática \ métodos públicos \ propiedades \ atributos de clases


https://github.com/tc39/proposal-class-fields
https://github.com/tc39/proposal-private-methods
https://github.com/tc39/proposal-static-class-features


En algunos idiomas hay un acuerdo para llamar a métodos privados con un espacio visible (" _ " - tal pieza, es posible que conozca este signo con el nombre incorrecto - subrayado) .


Por ejemplo, así:


 <?php class AdultContent { private $_age = 0; private $_content = '…is dummy example content (•)(•) —3 (.)(.) only for adults…'; function __construct($age) { $this->_age = $age; } function __get($name) { if($name === 'content') { return " (age: ".$this->_age.") → ".$this->_getContent()."\r\n"; } else { return 'without info'; } } private function _getContent() { if($this->_contentIsAllowed()) { return $this->_content; } return 'Sorry. Content not for you.'; } private function _contentIsAllowed() { return $this->_age >= 18; } function __toString() { return $this->content; } } echo "<pre>"; echo strval(new AdultContent(10)); // (age: 10) → Sorry. Content not for you echo strval(new AdultContent(25)); // (age: 25) → …is dummy example content (•)(•) —3 only for adults… $ObjectAdultContent = new AdultContent(32); echo $ObjectAdultContent->content; // (age: 32) → …is dummy example content (•)(•) —3 only for adults… ?> 

Déjame recordarte: esto es solo un acuerdo. Nada impide usar el prefijo para otros fines, usar un prefijo diferente o no usarlo en absoluto.


Personalmente, estoy impresionado con la idea de usar un espacio visible como prefijo para las funciones que devuelven this . Entonces se pueden combinar en una cadena de llamadas.


Los desarrolladores de la especificación EcmaScript fueron más allá e hicieron que el prefijo octotorp (" # " —lattice, hash) formara parte de la sintaxis.


El ejemplo anterior en ES 10 se puede reescribir de la siguiente manera:


 export default class AdultContent { //    #age = 0 #adult_content = '…is dummy example content (•)(•) —3 (.)(.) only for adults…' constructor(age) { this.#setAge(age) } //    static #userIsAdult(age) { return age > 18 } //   get content () { return `(age: ${this.#age}) → ` + this.#allowed_content } //   get #allowed_content() { if(AdultContent.userIsAdult(this.age)){ return this.#adult_content } else { return 'Sorry. Content not for you.' } } //   #setAge(age) { this.#age = age } toString () { return this.#content } } const AdultContentForKid = new AdultContent(10) console.log(String(AdultContentForKid)) // (age: 10) → Sorry. Content not for you. console.log(AdultContentForKid.content) // (age: 10) → Sorry. Content not for you. const AdultContentForAdult = new AdultContent(25) console.log(String(AdultContentForAdult)) // (age: 25) → …is dummy example content (•)(•) —3 (.)(.) only for adults… console.log(AdultContentForAdult.content) // (age: 25) → …is dummy example content (•)(•) —3 (.)(.) only for adults… 

El ejemplo es innecesariamente complicado para demostrar propiedades privadas, métodos y atributos a la vez. Pero en general, JS - agrada a la vista con su concisión en comparación con la versión de PHP. Sin función privada _... para usted, sin punto y coma al final de la línea, y un punto en lugar de "->" para profundizar en el objeto.


Getters nombrados. Para nombres dinámicos, objetos proxy.


Parecen ser insignificantes, pero después de cambiar a JS, cada vez hay menos ganas de volver a PHP.


Por cierto, los accesos privados solo están disponibles con Babel 7.3.0 y versiones posteriores.


Al momento de escribir, la versión más reciente de npmjs.com es 7.2.2


¡Espero con ansias la Etapa 4!




Shebang Grammar


https://github.com/tc39/proposal-hashbang


Hashbang es una forma en que Unix está familiarizado con la especificación de un intérprete para un archivo ejecutable:


 #!/usr/bin/env node //   'use strict'; console.log(1); 

 #!/usr/bin/env node //   export {}; console.log(1); 

Chrome SyntaxError: Invalid or&nbsp;unexpected token está lanzando un SyntaxError: Invalid or&nbsp;unexpected token en una SyntaxError: Invalid or&nbsp;unexpected token similar


Grandes números con BigInt


https://github.com/tc39/proposal-bigint


soporte de navegador

Soporte de navegador para primitiva BigInt ()


El entero máximo que se puede usar de forma segura en JavaScript (2⁵³ - 1):


 console.log(Number.MAX_SAFE_INTEGER) // 9007199254740991 

BigInt es necesario para usar números de precisión arbitrarios.


Este tipo se declara de varias maneras:


 //  'n'       910000000000000100500n // 910000000000000100500n //      BigInt()   BigInt( 910000000000000200500 ) // 910000000000000200500n //     -  BigInt( "910000000000000300500" ) // 910000000000000300500n //      1642  BigInt( "" ) \\ 

Este es un nuevo tipo primitivo:


 typeof 123; // → 'number' typeof 123n; // → 'bigint' 

Se puede comparar con números ordinarios:


 42n === BigInt(42); // → true 42n == 42; // → true 

Pero las operaciones matemáticas deben llevarse a cabo dentro de un tipo:


 20000000000000n/20n // 1000000000000n 20000000000000n/20 // Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions 

Unary menos es compatible, unary plus devuelve un error:


  -2n // -2n +2n // Uncaught TypeError: Cannot convert a BigInt value to a number 


globalThis : una nueva forma de acceder al contexto global


https://github.com/tc39/proposal-global


trabaja en cromo


Dado que las implementaciones de alcance global dependen de un motor en particular, tenía que hacer algo como esto antes:


 var getGlobal = function () { if (typeof self !== 'undefined') { return self; } if (typeof window !== 'undefined') { return window; } if (typeof global !== 'undefined') { return global; } throw new Error('unable to locate global object'); }; 

E incluso esta opción no garantizaba que todo funcionara con seguridad.


globalThis es una forma común para que todas las plataformas accedan al alcance global:


 //      globalThis.Array(1,2,3) // [1, 2, 3] //        globalThis.myGLobalSettings = { it_is_cool: true } //        globalThis.myGLobalSettings // {it_is_cool: true} 



import(dynamic)


https://github.com/tc39/proposal-dynamic-import


soporte de navegador

Soporte de navegador para importaciones dinámicas


Quería variables en las líneas de importación Con importaciones dinámicas, esto se hizo posible:


 import(`./language-packs/${navigator.language}.js`) 

La importación dinámica es una operación asincrónica. Devuelve una promesa de que, después de cargar el módulo, lo devuelve a la función de devolución de llamada.


Por lo tanto, puede cargar módulos, diferidos cuando sea necesario:


 element.addEventListener('click', async () => { //   await    const module = await import(`./events_scripts/supperButtonClickEvent.js`) module.clickEvent() }) 

Sintácticamente, esto se parece a una llamada a la función import() , pero no hereda de Function.prototype , lo que significa que no tendrá éxito en llamar a través de call o apply :


 import.call("example this", "argument") // Uncaught SyntaxError: Unexpected identifier 



import.meta: metainformación sobre el módulo cargado.


https://github.com/tc39/proposal-import-meta


trabaja en cromo


En el código del módulo cargado, se hizo posible obtener información sobre él. Ahora esta es solo la dirección en la que se cargó el módulo:


 console.log(import.meta); // { url: "file:///home/user/my-module.js" } 



JSON.stringify() método JSON.stringify()


https://github.com/tc39/proposal-well-formed-stringify


La Sección 8.1 de RFC 8259 requiere que el texto JSON intercambiado fuera de un ecosistema cerrado se codifique utilizando UTF-8, pero JSON.stringify puede devolver cadenas que contienen puntos de código que no están representados en UTF-8 (en particular, puntos de código sustitutos de U + D800 a U + DFFF)


Entonces la línea \uDF06\uD834 después de procesar JSON.stringify () se convierte en \\udf06\\ud834 :


 /*         */ JSON.stringify('\uDF06\uD834') '"\\udf06\\ud834"' JSON.stringify('\uDEAD') '"\\udead"' 

Esto no debería ser, y la nueva especificación lo corrige. Edge y Chrome ya se han actualizado.




Características obsoletas de RegExp


https://github.com/tc39/proposal-regexp-legacy-features


Especificación para funciones RegExp heredadas, como el método RegExp.$1 y RegExp.prototype.compile() .




Métodos de cadena de prototipo .trimStart() y .trimEnd()


https://github.com/tc39/proposal-string-left-right-trim


trabaja en cromo


Por analogía con los métodos .padStart() y .padEnd() , corta el espacio en blanco al principio y al final de la línea, respectivamente:


 const one = " hello and let "; const two = "us begin. "; console.log( one.trimStart() + two.trimEnd() ) // "hello and let us begin." 



.matchAll () es un nuevo método de cadena prototipo.


https://github.com/tc39/proposal-string-matchall


trabaja en cromo


Funciona como el método .match() con la bandera g activada, pero devuelve un iterador:


 const string_for_searh = 'olololo' //         string_for_searh.match(/o/) // ["o", index: 0, input: "olololo", groups: undefined] //       string_for_searh.match(/o/g) // ["o", "o", "o", "o"] //   string_for_searh.matchAll(/o/) // {_r: /o/g, _s: "olololo"} //        , //      .match    for(const item of string_for_searh.matchAll(/o/)) { console.log(item) } // ["o", index: 0, input: "olololo", groups: undefined] // ["o", index: 2, input: "olololo", groups: undefined] // ["o", index: 4, input: "olololo", groups: undefined] // ["o", index: 6, input: "olololo", groups: undefined] 

El argumento debe ser una expresión regular; de lo contrario, se generará una excepción:


 'olololo'.matchAll('o') // Uncaught TypeError: o is not a regexp! 







Resumen


La etapa 4 trajo más cambios cosméticos. El interés es la etapa 3 . La mayoría de las sugerencias en Chrome ya están implementadas, y las propiedades de los objetos realmente están deseando.






Correcciones en el articulo



Si notó una inexactitud en el artículo, un error o hay algo para complementar, puede escribirme un mensaje personal , pero es mejor usar el repositorio de artículos https://github.com/KasperGreen/es10 usted mismo. Por su contribución activa, otorgaré una medalla de imán amarilla con KDPV.


Materiales relacionados


Material en ingles Versión actual del estándar Ecma-262


Material en ingles Borrador de la próxima versión del estándar Ecma-262


ECMAScript


Nuevos # campos de clase privada en JavaScript


Artículo sobre Habré Descripción general de los estándares ES7, ES8 y ES9


Shebang


Artículo sobre Habré BigInt - aritmética larga en JavaScript


Artículo sobre Habré Ruta del módulo JavaScript


Material en ingles ¿Por qué no privado x


Artículo sobre Habré Propuesta de ECMAScript: Array.prototype. {Flat, flatMap}


Campos de clase públicos y privados.


JavaScript: el gran todo por qué




UPD (marzo):


Cambió el estado a Etapa - 4 :


.trimStart() y .trimEnd() - métodos de cadena prototipo # ;


.matchAll() - .match() con la bandera global # ;


KDPV alternativo con un imán amarillo de elfafeya.art
Foto por: kasper.green; Imán amarillo: elfafeya.art & kasper.green

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


All Articles