O que tem de novo no ES2020(ES11)
Tags: javascript, webdev, node
Published: 2020-06-23 00:36:36

Vamos ver mais de perto as coisas incríveis que chegaram agora na nova especificação do _ECMAScript_! 🤩

Todo ano uma nova versão da especificação _ECMAScript_ sai com as propostas de _features,_ para isso o[comitê da TC39 faz um exaustivo processo](https://tc39.es/process-document/)refinando as propostas até serem serem aceitas e passaram para seu estado final,o [stage 4](https://github.com/tc39/proposals/blob/master/finished-proposals.md), que define o que estará presente no proximo _draft_.  
Essas _features_ serão consideradas **estáveis** assim que dois navegadores as implementarem.

Esse processo garante uma melhora constante no estado da arte do Javascript 👩‍🎨.

Todas as features para a especificação de 2020(_ES2020_) **estão finalizadas,** significando que estão prontas para serem **implementadas em navegadores, engines e ferramentas!**

➡️ BigInt  
➡️ Private Methods  
➡️ Optional Chaining  
➡️ Nullish coalescing Operator  
➡️ String.prototype.matchAll  
➡️ globalThis  
➡️ for-in mechanics  
➡️ Promise.allSettled  
➡️ Dynamic Imports  
➡️Module Namespace Exports

### As propostas 🖋

#### [BigInt](https://github.com/tc39/proposal-bigint) 🧮

Quem está habituado a usar números em JS já sofreu muito em relação a limitação do seu tipo Number **,** que não passa de um double de 64 bits, tendo assim uma limitação de até um certo número que podemos fazer operações de forma “segura”.

```javascript
// Número máximo seguro no JS
Number.MAX\_SAFE\_INTEGER // 9007199254740991
```

Para isso é comum dependermos de bibliotecas externas para tentar lidar de forma mais segura com valores altos.

BigInt é agora o **sétimo tipo primitivo** dentro da linguagem, servindo somente pra lidar somente com precisão de inteiros. Pois uma variável deste tipo pode representar 2⁵³ números.

Com a nova especificação podemos indicar o tipo BigInt somente colocando uma letra n no final do número, denotado para a engine Javascript(v8 ou qualquer outra) como o número ser tratado.

```javascript
const numeroGrande = 100000000000000000000000000000n;
console.log(numeroGrande \* 2n); // 200000000000000000000000000000n
```

Podemos fazer _casting_ para esse novo tipo desta forma.

```javascript
console.log( BigInt ( Number.MAX\_SAFE\_INTEGER))
// 9007199254740991n
```

É importante lembrar que essa coersão de Number para BigInt pode causar perda de precisão então o ideal é já definir números como BigIntquando se tem a certeza que eles podem ser grandes.

BigInt já foi implementado nos maiores navegadores como Chrome, Firefox, opera e a versão 10.4 do Node.js e está bem **estável ✅**

**📖** [**Especificação**](https://tc39.es/ecma262/#sec-bigint-objects)  
**🗼** [**Plugin Babel**](https://babeljs.io/docs/en/babel-plugin-syntax-bigint)

_(OBS: O plugin babel não implementa o novo tipo apenas permite que você use essa sintaxe. Ou seja, o código “const foo = 1n” vai buildar, mas a variável não vai poder usar um número do bigint. (Obrigada_ [_Macabeus_](https://twitter.com/bmacabeus)_))_

#### [Private Methods](https://github.com/tc39/proposal-private-methods)🔒

_JS_ sempre foi uma linguagem orientada a objetos mas por sua implementação com base em protótipo ao invés de classes, apesar de termos a sintaxe especial de Classdesde de a _ES2015,_ por conflitos de decisões de implementação não tínhamos como fazer métodos ou campos privados nativamente.

Quando usamos classes em Javascript temos como padrão nomear elementos privados com um \_na frente como meio de diferenciação.

Com a nova especificação colocar o sinal de #na frente da variável ou função já vai definir que o **não se deve ter acesso a ele em outros contextos além da própria classe**.

Apesar de parecer contra intuitivo, essa decisão se deve exatamente ao fato de que muitas bibliotecas já aderiram o sublinhado \_ como meio de marcar campos privados, sendo um meio de evitar alterações já existentes.

Isso pode causar um estranhamento também pra quem vem do _Typescript_ cuja sintaxe já amplamente conhecida para definir se algo é privado também é o \_ .

Dessa forma podemos escrever classes similares a essa:

```javascript
class Counter {
  #x = 0; // Define uma variável privada
  increment() {
this.#x++; // Incrementa a variável privada
  }
  decrement() {
this.#x--; // Decrementa a variável privada
  }
  getX(){
return this.#x;
  }
}

const c = new Counter();

console.log(c.getX()); // 0 -> Valor é exposto pelo metodo getX
```

Tentar pegar o valor da variável privada diretamente não é viável pois ela não pode ser acessada fora do contexto da classe.

```javascript
c.#x => 🙅‍♀Uncaught SyntaxError: Private field '#x'
```

Os métodos modificam o campo x e o resultado final retornado por por getX é o valor -1.

```javascript
c.increment(); 
c.decrement();
c.decrement();
console.log(c.getX()); // -1 -> Valor é modificado e depois exposto
```

Supondo que no meu exemplo não quero que o contador chegue em valor abaixo de 0 e quero criar uma função auxiliar privada para fazer essa verificação.

```javascript
class Counter {
  #x = 0;     
  increment() {
this.#x++;       
  }
  #isPositive() {
return this.#x > 0
  }
  decrement() {
if ( this.#isPositive()) this.#x--;  
  // Chama o método privado para verificar se o valor x é positivo
  }
  getX(){
return this.#x;
  }
}

const c = new Counter();
```

Assim como a propriedade privada, não posso chamar o método novo fora do contexto da classe.

```javascript
c.#isPositive() => 🙅‍♀Uncaught SyntaxError: Private method '#x'
```

Desta forma ao chamar a função decrement podemos ter a garantia que nosso valor não será negativo.

```javascript
c.decrement();
console.log(c.getX()); // 0
```

Isso é de extrema importância pois até então tínhamos dificuldade de seguir os **princípios de SOLID** pois não tínhamos como suprir o **Open/Closed** principle.

Essa feature já está na ultima versão do _Chrome_ e do _Node v12_.

**📖** [**Especificação**](https://tc39.es/proposal-private-methods/)  
**🗼** [**Plugin Babel**](https://babeljs.io/docs/en/babel-plugin-proposal-private-methods)

#### [Optional Chaining Operator](https://github.com/tc39/proposal-optional-chaining) ❓

Quem nunca passou ou ouviu falar do famoso _“Cannot read property of undefined”_? Javascript pode ser _tricky_ quando estamos lidando com valores _nulos_ ou _undefined_.

Pelo dinamismo do Javascript precisamos muitas vezes fazer **múltiplas verificações para conseguir pegar propriedades de qualquer objeto** para tentar evitar receber um erro pois uma delas está nula.

Supondo um objeto com dados de um "usuário" que pode_(ou não)_ conter informações do perfil de uma pessoa.

```javascript
user // undefined
user.profile // Error : _Cannot read property of undefined_  
user.profile.name // Error : _Cannot read property of undefined_
```

Quando tentamos pegar a propriedade de um objeto, o código espera que seja um objeto válido, jogando um erro caso o seu valor seja inesperado.

Quando não temos a garantia dos valores e temos de pegar por exemplo, uma propriedade name em segundo nível do objeto teríamos de fazer diversas verificações.

```javascript
if (user != undefined && user.profile != undefined) {
 user.profile.name 
}
```

Adicionando o novo operador interrogação antes do ponto nós conseguimos interagir com o caminho opcional. Caso ele exista, temos acesso ao resultado esperado.

```javascript
const user = {profile: {name: "Maria"}}


user ?.profile ?.name // “Maria”
```

Caso algum valor comparado pelo operador não exista ele retorna apenas um _undefined_ sem mais erros.

```javascript
const user = {}

user ?.profile ?.name // Undefined
```

Isso não se limita a objetos ou arrays mas também pode ser usado em funções a serem executadas.

```javascript
user.profile.checarAlgo ?.(...argumentos)
```

Essa sintaxe também pode ser usada para acesso dinâmico da propriedade

```javascript
user.profile ?.[nomeDaPropriedade]
```

Isso é especialmente interessante quando queremos um valor dentro de uma estrutura muito grande que precisamos sempre ficar checando se cada parte da estrutura existe ou não.

```javascript
// Com operador
a ?.b[3].c?.(x).d
// Sem operador
a == null ? undefined : a.b[3].c == null ? undefined : a.b[3].c(x).d
```

O operador de **Optional Chaining** permite lidar com a talvez existência de valores de forma limpa, consistente e sem que a gente se repita fazendo múltiplas verificações desnecessárias para o mesmo elemento. A sintaxe foi inspirada de linguagens como _C#_ e _Swift_ e também certamente do _Typescript_, que já tem essa funcionalidade nativa.

A funcionalidade já está implementada nos principais navegadores, engines e ferramentas!

**📖** [**Especificação**](https://tc39.es/proposal-private-methods/)  
**🗼** [**Plugin Babel**](https://babeljs.io/docs/en/babel-plugin-proposal-private-methods)

#### [Nullish Coalescing Operator](https://github.com/tc39/proposal-nullish-coalescing) ⏸

É bem comum fazermos verificações para checar se um valor especifico é **falsey** (_null, undefined, etc)_ para tratarmos da forma mais apropriada para não quebrarmos nosso código ou expormos acidentalmente esses valores para o usuário.

Quando queremos acessar propriedades de um objeto que não temos certeza de sua existência é comum usarmos um valor _default_. Tentamos algo similar a isso:

```javascript
user.profile.name == undefined ? “Anonymous” : person.profile.name
user.profile.age == undefined ? 0 : person.profile.age
```

Também podemos tentar expressar a mesma coisa por meio do operador barra-barra ou OR => ||.

```javascript
false || “Texto teste” // Texto teste
undefined || “Texto teste” // Texto teste
null || "Texto teste" // Texto teste
NaN || "Texto teste" //Texto teste
```

Essa solução é realmente ótima quando queremos lidar com qualquer tipo que consideramos **"Falsey"**

O **Nullish Coalescing** nos apresenta um operador de duas interrogações (??) que nos trás uma verificação mais _type strict p_ermitindo um valor _default_ **apenas** quando temos um _null_ ou _undefined_.

```javascript
false ?? “Texto teste” // false
undefined ?? “Texto teste” // Texto teste
null ?? ”Texto teste” // Texto teste
NaN ?? “Texto teste” // NaN
```

Podemos simplificar o exemplo anterior desta forma:

```javascript
user.profile.name == undefined ? “Anonymous” : person.profile.name
user.profile.name **??** “Anonymous”
```

Supondo que no nosso mesmo objeto user, podemos dentro de profile ter tanto um name quanto um nickname.  
Se em um campo de nome devo mostrar o name **OU** onickname **OU** um valor padrão, nossa solução comum seria algo similar a:

```javascript
if (person.profile.nickname == undefined) { 
if (person.profile.name == undefined) {
    “Anonymous”
  } else {
    return person.profile.name
  }
} else {
  return person.profile.nickname
}
```

Com nosso novo operador se torna apenas:

```javascript
person.profile.nickname ?? person.profile.name ?? “Anonymous”.
```

Essa sintaxe já é [bem conhecida](https://en.wikipedia.org/wiki/Null_coalescing_operator) em outras linguagens como _C#_ e _Swift,_ está presente no _PHP_ desde sua versão 7 e já está começando a ser implementada nos maiores navegadores.

**📖** [**Especificação**](https://tc39.es/proposal-nullish-coalescing/)  
**🗼** [**Plugin Babel**](https://babeljs.io/docs/en/babel-plugin-proposal-nullish-coalescing-operator)

#### [String.protype.matchAll](https://github.com/tc39/proposal-string-matchall) 💕

O novo metodomatchAll() está relacionado a expressões regulares.  
Ele recebe uma expressão como argumento e retorna um iterador com todos os resultados que deram "_match_" com essa expressão.

Podemos acessar os casos iterando o seu resultado.

```javascript
const onlyABC = /[a-c]/g
const str = 'abc'
const matches = str.matchAll(onlyABC)

for (const match of matches) {
  console.log(match);
}

// ["a", index: 0, input: "abc", groups: undefined]
// ["b", index: 0, input: "abc", groups: undefined]
// ["c", index: 0, input: "abc", groups: undefined]
```

Após a interação pelo _for..of_ nosso iterador fica cansado, então temos de chamar o matchAll() novamente se requeremos os resultados novamente.

```javascript
const arrMatches = [...str.matchAll(onlyABC)]

// [["a", index: 0, input: "abc", groups: undefined],
    ["b", index: 0, input: "abc", groups: undefined],
    ["c", index: 0, input: "abc", groups: undefined]]
```

Ok, mas qual o beneficio?  
Agora conseguimos **um resultado mais complexo para nossa _regex_ além do _match_ em si** , e isso fica visível em casos mais complexos em temos diversos agrupamentos.

```javascript
const getTest = /t(e)(st(\d?))/g;
const str = 'test1test2'

const arrMatches= [...str.matchAll(getTest)];

array[0];
// ['test1', 'e', 'st1', '1', index: 0, input: 'test1test2', length: 4]
array[1];
// ['test2', 'e', 'st2', '2', index: 5, input: 'test1test2', length: 4]

str.match(getTest); 
// Array ['test1', 'test2']
```

A escolha de retornar um iterador é por uma mera questão de performance, já que podemos facilmente coletar esses valores por meio do _spread operador_ como no exemplo acima.  
Essa feature já está também vastamente implementada.

**📖** [**Especificação**](https://tc39.es/proposal-string-matchall/)

#### [Standardized globalThis object 🌍](https://github.com/tc39/proposal-global)

O que para alguns é um monstro para outros pode ser benção, agora temos padronizado o **THIS GLOBAL**. Ou seja, um contexto da aplicação global independente de _runtime_.

O globalThis se refere ao objeto global, independente de onde você está executando o código.   
Sendo assim você pode em produção para um projeto multiplataforma escrever isso:

```javascript
globalThis.variavelGlobalzassa = "Irraaa 🤠🐎"
```

Brincadeiras a parte, essa padronização se deve ao fato que por JS ser multiplataforma e portanto, um único código pode rodar no Node, no navegador ou em qualquer outro contexto.  
Sendo assim, fica difícil ter um objeto global sem uma padronização se isso vai ser em um window (Browser) ouglobal (Node) por exemplo.

**📖** [**Especificação**](https://tc39.es/proposal-global/)

#### Promise.allSettled 🚦

O metodoPromise.allSettled recebe um _array_ de _Promises_ e só se resolve quando todas as elas estiverem resolvidas, seja como _fulfilled_ ou _rejected,_ com o estado de cada uma delas.

Ou seja, com ele podemos criar uma nova _Promise_ que só retorna quando todas as _Promises_ passadas forem concluídas, **independente de resultado** , sem a necessidade de um encadeamento.

O método retorna um _array_ com o status das _Promises_ com o seu respectivo valor, caso _fullfilled,_ ou a razão da falha, caso _rejected_.

Nesse exemplo temos colocamos duas promises no Promise.allSettled , uma com resolução e outra com falha, e damos console.log no resultado!

```javascript
const stuff1 = new Promise ((res, rej) => res({x: 10, test: "🤠"}));
const stuff2= new Promise ((res, rej) => rej(Error ("Deu ruim 😭")));

Promise.allSettled([stuff1, stuff2])
  .then(data => **console**.log(data)); 
// [ 
//   Object { status: "fulfilled", value: {x: 10, test: "🤠"}},
//   Object { status: "rejected", reason: "Deu ruim 😭"} 
// ]
```

Temos como resultado um array com dois objetos, ambos com o status de resolução da _Promise_. A que foi resolvida tem uma propriedade value que contêm o conteúdo da _Promise_ e que falhou tem a propriedade reason_q_ue fala a razão do erro.

Já tentávamos fazer algo similar resolvendo múltiplas promises simultâneas com o Promise.all .

```javascript
Promise.all([stuff1, stuff2])
  .catch(err => console.log(err)); // Deu ruim 😭
```

Se colocássemos as duas promises o Promise.all joga pra cima a falha do stuff2para que você trate e ignora completamente as _Promises_ que foram resolvidas. **Não tínhamos até então um método que “não ligasse” pros resultados de cada uma das _Promises_.**

A motivação vem da implementação dos [4 combinators de promises](https://v8.dev/features/promise-combinators), que são os principais casos implementados em bibliotecas ou linguagens para lidar com assincronismo.

Nele temos o Promise.all e oPromise.race que já foram especificados na _ES2015,_ o Promise.allSettled , e um futuro metodo a ser incluído em uma **próxima proposta** chamado Promise.any .

O Promise.any receberia também uma lista de _Promises_ e retornaria quando qualquer uma fosse resolvida.

**📖** [**Especificação**](https://tc39.es/proposal-promise-allSettled/)

#### [for-in mechanics](https://github.com/tc39/proposal-for-in-order) 🎡

Quem acompanhou as mudanças sabe da existência dessa feature. Aparentemente a especificação da forma como for-in deve ser implementada foi na verdade apenas mais refinada pois a sua ultima versão foi pouco especifica em relação a que ordem o for (x in y)deve rodar levando a _engines_ não entraram em um consenso sobre como implementar.

**📖** [**Especificação**](http://tc39.es/proposal-for-in-order/)

#### [Dynamic Import / Import()](https://github.com/tc39/proposal-dynamic-import) 🚢

O import dinâmico retorna uma uma promise para o objeto do modulo do namespace que foi requisitado. Sendo assim, **agora poderemos colocar um import dentro de uma variável e chamar usando async/await .**

Para que isso é importante? Podemos importar nossos arquivos de forma “_Lazy_” ou seja, **apenas executar código dos arquivos conforme queremos.**

Isso garante um controle da execução código muito maior em _runtime_ podendo impactar muito na performance pois **executar todos os arquivos que são importados imediatamente pode ser um _overhead._**

Se por exemplo, estou usando funções de utilidade de outro arquivo ou pacote que são utilizadas apenas algum momento especifico do meu código.  
_Será que faz sentido mais importá-las quando o arquivo foi executado ou quando forem(e se forem) realmente utilizadas?_

```javascript
//utils.js

...muitas funções e coisas...

const add = (x, y) => x + y;

export { add };
```

Se estou fazendo uso dele em outro arquivo podemos importá-lo apenas antes de usar a função importada em especifico.

```javascript
const doMathStuff = async (x, y) => {
const math = await import('./utils.js');
console.log(math.add(5, 10));
};
```

Em _runtime_ essa função não vai ser carregada a não ser que chamada, portanto pode até mesmo **nunca ser carregada se nunca for usada**.

Isso é extremamente crucial por exemplo em _front-end_ em que queremos minimizar o máximo possível o conteúdo sendo executado. Muito código sendo executado inconsequentemente ao abrir um site pode ser bem custoso_(_[_ver “V8 Start-up Performance”_](https://medium.com/reloading/javascript-start-up-performance-69200f43b201)_)._

Isso é conhecido como _code splitting_ e muito provávelmente seu código já está sendo pelo menos um pouco otimizado pelo próprio _babel_ com _webpack_, ou qualquer outro _module bundle_ dessa forma.

O _webpack_ por exemplo faz algo chamado ["Tree shaking"](https://webpack.js.org/guides/tree-shaking/) , em que ele basicamente monta uma arvore de dependências do seu próprio código e otimiza por exemplo, removendo o que não está sendo usado.

Os imports dinâmicos ficam de fora do _Tree Shaking_ do _webpack_ _(ver_ [_Dynamic Import and Tree Shaking in JavaScript_](https://medium.com/better-programming/dynamic-import-and-tree-shaking-in-javascript-ddc2f3cd69f)_)_, então é importante questionar quando vale a pena deixar o controle na nossa mão ou em outras ferramentas.

**📖** [**Especificação**](https://github.com/tc39/proposal-export-default-from)  
**🗼** [**Plugin babel**](https://babeljs.io/docs/en/babel-plugin-proposal-export-default-from)  
**🌲** [**Otimização JS com tree shaking**](https://developers.google.com/web/fundamentals/performance/optimizing-javascript/tree-shaking)

#### [Module Namespace Exports](https://github.com/tc39/proposal-export-ns-from) 🛄

Nos módulos podemos usar a seguinte sintaxe para importarmos todos os elementos de por exemplo, um arquivo utils:

```javascript
import * from './utils.js'
```

Mas não podíamos exportar de forma similar **nativamente** e tínhamos de exportar o próprio modulo dentro de um objeto.

```javascript
import default as utils from './utils.js'
export { utils }
```

Mas agora temos uma sintaxe similar para exportar todo o conteúdo do módulo de forma similar!

```javascript
export * from './utils.js'
```

Também podemos renomear o conteúdo exportado como nos exemplos:

```
export * as utils from './utils.js'
export { add as soma } from './utils.js'
```

A ideia é bem simples mas essa simetria deixa mais consistente a forma como lidamos com nossos projetos.

**📖** [**Especificação**](https://tc39.es/proposal-export-ns-from/)  
**🗼** [**Plugin Babel**](https://babeljs.io/docs/en/babel-plugin-proposal-export-namespace-from)

— — — — —

"Quero usar essas funcionalidade tipo,  **AGORA**!!"

Basta modificar o seu arquivo.babelrc alguns destes novos plugins

```javascript
{
  "plugins": [
    "@babel/plugin-proposal-nullish-coalescing-operator",
    "@babel/plugin-proposal-optional-chaining",
    "@babel/plugin-proposal-class-properties",
    "@babel/plugin-proposal-private-methods",
    "@babel/plugin-syntax-bigint"
  ]
}
```

Caso você não tenha nada configurado a forma mais simples seria usando o [Parcel bundler](https://parceljs.org/) no seu projeto instalando-o como dependência

```bash
$ yarn add parcel-bundler
```

E em seguida configurando nos scripts do seu _package.json_ para que ele execute os seu projeto.

```javascript
// package.json

...

"scripts": {
  "start": "parcel index.js"
},
```

### Conclusão

**Javascript é uma linguagem viva** e vemos nos últimos anos uma evolução constante para melhorar o desenvolvimento web e isso certamente é uma tarefa difícil para uma uma comunidade também crescendo e evoluindo muito rápido com a linguagem.

Espero que vocês tenham gostado!! 👏 👏 👏 👏 👏 👏

**Quem gostou bate palminha pra que o artigo alcance outros amiguinhos.**  
_❤️🧡💛💚💙💜._

[tc39/proposals](https://github.com/tc39/proposals/blob/master/finished-proposals.md)