EcmaScript 10 - JavaScript deste ano (ES2019)

A padronização da JS mudou para um ciclo de atualização de um ano, e o início do ano é um ótimo momento para descobrir o que nos espera no aniversário - a décima edição do EcmaScript!


ES 9 é a versão atual da especificação .


ES 10 ainda é um rascunho .


Até o momento, o estágio 4 # tem apenas algumas sugestões.


E no Estágio 3 # - uma dúzia inteira!


Destes, na minha opinião, os mais interessantes são os campos privados das classes # , gramática shebang para scripts # , números de precisão arbitrária # , acesso ao contexto global # e importações dinâmicas # .



KDPV: Ímã amarelo com a inscrição "JS ES10" na tela do monitor - de kasper.green & elfafeya.art
Foto de: kasper.green; Ímã amarelo: elfafeya.art & kasper.green


Conteúdo


Cinco estágios


Etapa 4 - Final #


catch - o argumento se tornou opcional # ;


Symbol().description - acessador da descrição do símbolo # ;


' EcmaScript' - compatibilidade aprimorada com o formato JSON # ;


.toString() - método de protótipo atualizado # .


Object.fromEntries() - criando um objeto a partir de uma matriz de pares - chave \ valor # ;


.flat() e .flatMap() são métodos de protótipo # array .




Etapa 3 - Pré-lançamento #


# - tudo é privado nas aulas, através do octotorp # ;


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


BigInt() - uma nova primitiva, para números de precisão arbitrários # ;


globalThis - uma nova maneira de acessar o contexto global # ;


import(dynamic) - número de importação dinâmico ;


import.meta - informações meta sobre o módulo carregado # ;


JSON.stringify() - correção do método # ;


RegExp - recursos obsoletos ;


.trimStart() e .trimEnd() - métodos de string de protótipo # ;


.matchAll() - .match() com o sinalizador global # ;


Resultados #




Cinco etapas


Estágio 0Strawman Basting Uma idéia que pode ser implementada através do plugin Babel .;


Etapa 1Proposta Proposta Verificação da viabilidade da ideia.


Etapa 2Rascunho Início do desenvolvimento da especificação;


Etapa 3 ↓ Especificação de visualização do candidato candidato ;


Etapa 4 ֍ Finalizada A versão final da especificação para este ano está concluída.




Consideraremos apenas o Estágio 4 - o padrão de fato.


E o Estágio 3 - que está prestes a se tornar parte dele.





֍ Etapa 4


Essas mudanças já são padrão.


Argumento opcional a ser catch


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


Antes do ES 10, o catch exigia um argumento necessário para coletar informações de erro, mesmo que não fosse usado:


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


O Edge ainda não foi atualizado para o ES 10 e espera-se que ocorra um erro.


Começando com a edição ES 10, os parênteses podem ser omitidos e a catch se tornará como duas gotas de água como try .



Meu Chrome já foi atualizado para o ES 10 e, em alguns lugares, para o Estágio 3 . Outras capturas de tela serão do Chrome


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



Acessar descrições de links simbólicos


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


Uma descrição simbólica do link pode ser obtida indiretamente usando o método toString ():


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

A partir do ES 10, os caracteres têm uma propriedade de descrição que é somente leitura. Permite obter uma descrição do símbolo sem danças com um pandeiro:


 symbol_link.description // "Symbol description" 

Se a descrição não for especificada, ela retornará - undefined :


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



Seqüências de caracteres EcmaScript compatíveis com JSON


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


O EcmaScript, antes de sua décima edição, afirma que o JSON é um subconjunto do JSON.parse , mas isso não é verdade.


As linhas JSON podem conter separadores de linha não blindados U+2028 LINE SEPARATOR e os parágrafos U+2029 PARAGRAPH SEPARATOR .


O ECMAScript alinha até a décima versão - não.


Se você chamar eval() no Edge com a string "\u2029" ,
ele se comporta como se tivéssemos quebrado uma linha - bem no meio do código:




Com as linhas ES 10 - está tudo bem:





Refinamento do método protótipo .toString()


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


Alterar metas
  • remova o requisito incompatível com versões anteriores:

Se a implementação não puder criar uma sequência de código-fonte que atenda a esses critérios, ela deverá retornar uma sequência cuja eval lançará uma exceção com um erro de sintaxe.

  • esclarecer um requisito "funcionalmente equivalente";


  • padronizar a representação de string de funções internas e objetos host;


  • esclarecer os requisitos de apresentação com base nas "características reais" de um objeto;


  • certifique-se de que a análise da string contenha o mesmo corpo da função e lista de parâmetros que o original;


  • para funções definidas usando o código ECMAScript, toString deve retornar um fragmento do texto de origem do início do primeiro token até o final do último token correspondente à construção gramatical correspondente;


  • para objetos funcionais internos, toString não deve retornar nada além de uma NativeFunction;


  • para objetos chamados que não foram definidos usando o código ECMAScript, toString deve retornar um NativeFunction;


  • para funções criadas dinamicamente (construtores de função ou gerador) toString deve sintetizar o texto de origem;


  • para todos os outros objetos, toString deve lançar uma exceção 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" 



Criando um objeto usando o método Object.fromEntries()


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


trabalha em cromo


Análogo de _.fromPairs de lodash :


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



Matrizes unidimensionais com .flat() e .flatMap()


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


trabalha em cromo


A matriz adquiriu os protótipos .flat() e .flatMap() , que geralmente são semelhantes às implementações de lodash , mas ainda apresentam algumas diferenças. Argumento opcional - define a profundidade máxima da travessia da árvore:


 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 chamar consecutivamente .map().flat() . A função de retorno de chamada passada para o método deve retornar uma matriz que se tornará parte de uma matriz plana comum:


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

Usando apenas .flat() e .map() , o exemplo pode ser reescrito assim:


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

Observe também que .flatMap() , diferentemente de .flat() não possui configurações de profundidade de rastreamento. Portanto, apenas o primeiro nível será colado.







֍ Etapa 3


Propostas que emergiram do status de rascunho, mas ainda não entraram na versão final do padrão.


Métodos privados \ estáticos \ públicos \ propriedades \ atributos de classes


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


Em alguns idiomas, existe um acordo para chamar métodos privados com um espaço visível (" _ " - uma peça, você pode conhecer esse sinal com o nome errado - sublinhado) .


Por exemplo, assim:


 <?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… ?> 

Deixe-me lembrá-lo - isso é apenas um acordo. Nada impede o uso do prefixo para outros fins, o uso de um prefixo diferente ou a não utilização.


Pessoalmente, estou impressionado com a idéia de usar um espaço visível como prefixo para funções que retornam this . Para que eles possam ser combinados em uma cadeia de chamadas.


Os desenvolvedores da especificação EcmaScript foram além e tornaram o prefixo- octotorp (" # " - lattice, hash) parte da sintaxe.


O exemplo anterior no ES 10 pode ser reescrito da seguinte maneira:


 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… 

O exemplo é desnecessariamente complicado para demonstrar propriedades, métodos e atributos privados de uma só vez. Mas, em geral, o JS - agrada aos olhos com sua concisão em comparação com a versão PHP. Nenhuma função privada _... para você, sem ponto e vírgula no final da linha e um ponto em vez de "->" para aprofundar o objeto.


Getters nomeados. Para nomes dinâmicos, objetos proxy.


Parece pouco, mas depois de mudar para JS, há cada vez menos desejo de retornar ao PHP.


A propósito, acessadores privados estão disponíveis apenas com o Babel 7.3.0 e posterior.


No momento da redação deste artigo, a versão mais recente do npmjs.com é 7.2.2


Ansioso pela Etapa 4!




Gramática Shebang


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


Hashbang é uma maneira que o Unix está familiarizado com a especificação de um intérprete para um arquivo executável:


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

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

No momento, o Chrome está lançando um SyntaxError: Invalid or&nbsp;unexpected token em um SyntaxError: Invalid or&nbsp;unexpected token semelhante


Grandes números com BigInt


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


suporte ao navegador

Suporte do navegador para a primitiva BigInt ()


O número inteiro máximo que pode ser usado com segurança no JavaScript (2⁵³ - 1):


 console.log(Number.MAX_SAFE_INTEGER) // 9007199254740991 

O BigInt é necessário para usar números de precisão arbitrários.


Este tipo é declarado de várias maneiras:


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

Este é um novo tipo primitivo:


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

Pode ser comparado com números comuns:


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

Mas operações matemáticas devem ser realizadas dentro de um tipo:


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

Unário menos é suportado, unário mais retorna um erro:


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


globalThis - uma nova maneira de acessar o contexto global


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


trabalha em cromo


Como as implementações de escopo global dependem de um mecanismo específico, você precisava fazer algo assim 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 mesmo essa opção não garante que tudo funcione com certeza.


globalThis é uma maneira comum de todas as plataformas acessarem o escopo 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


suporte ao navegador

Suporte do navegador para importações dinâmicas


Eu queria variáveis ​​nas linhas de importação Com importações dinâmicas, isso se tornou possível:


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

A importação dinâmica é uma operação assíncrona. Retorna uma promessa que, após carregar o módulo, retorna à função de retorno de chamada.


Portanto, você pode carregar módulos - adiados quando necessário:


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

Sintaticamente, isso se parece com uma chamada para a função import() , mas não herda de Function.prototype , o que significa que não terá êxito ao chamar por call ou apply :


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



import.meta - informações meta sobre o módulo carregado.


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


trabalha em cromo


No código do módulo carregado, foi possível obter informações sobre ele. Agora, este é apenas o endereço no qual o módulo foi carregado:


 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


A seção 8.1 da RFC 8259 exige que o texto JSON trocado fora de um ecossistema fechado seja codificado usando UTF-8, mas o JSON.stringify pode retornar cadeias contendo pontos de código que não são representados no UTF-8 (em particular, pontos de código substitutos de U + D800 a U + DFFF)


Portanto, a linha \uDF06\uD834 após o processamento de JSON.stringify () se transforma em \\udf06\\ud834 :


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

Isso não deveria ser, e a nova especificação corrige isso. Edge e Chrome já foram atualizados.




Recursos RegExp preteridos


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


Especificação para funções herdadas de RegExp , como o método RegExp.$1 e RegExp.prototype.compile() .




Métodos de cadeia de caracteres de protótipo .trimStart() e .trimEnd()


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


trabalha em cromo


Por analogia com os métodos .padStart() e .padEnd() , corte o espaço em branco no início e no final da linha, respectivamente:


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



.matchAll () é um novo método de string de protótipo.


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


trabalha em cromo


Funciona como o método .match() com o sinalizador g ativado, mas retorna um 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] 

O argumento deve ser uma expressão regular, caso contrário, uma exceção será lançada:


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







Sumário


O estágio 4 trouxe mais mudanças cosméticas. O interesse é o estágio 3 . A maioria das sugestões no Chromeestá implementada e as propriedades dos objetos estão realmente ansiosas.






Correções no artigo



Se você notou uma imprecisão no artigo, um erro ou há algo para complementar, pode me escrever uma mensagem pessoal , mas é melhor usar o repositório de artigos https://github.com/KasperGreen/es10 . Como contribuição ativa, concederei uma medalha magnética amarela com o KDPV.


Materiais relacionados


Material em inglês Versão atual do padrão Ecma-262


Material em inglês Rascunho da próxima versão do padrão Ecma-262


ECMAScript


Novos # campos de classe privada em JavaScript


Artigo sobre Habré Visão geral dos padrões ES7, ES8 e ES9


Shebang


Artigo sobre Habré BigInt - aritmética longa em JavaScript


Artigo sobre Habré Caminho do módulo JavaScript


Material em inglês Por que não privado x


Artigo sobre Habré Proposta ECMAScript: Array.prototype. {Flat, flatMap}


Campos de classe pública e privada


JavaScript: O grande poço inteiro Por que




UPD (março):


O status foi alterado para Estágio - 4 :


.trimStart() e .trimEnd() - métodos de string de protótipo # ;


.matchAll() - .match() com o sinalizador global # ;


KDPV alternativo com um ímã amarelo de elfafeya.art
Foto de: kasper.green; Ímã amarelo: elfafeya.art & kasper.green

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


All Articles