Bom dia amigos!
Este artigo enfoca os recursos de JavaScript que serão apresentados na nova versão da especificação (ECMAScript 2021, ES12).
Será sobre o seguinte:
- String.prototype.replaceAll ()
- Promise.any ()
- WeakRefs
- Operadores de atribuição booleana
- Separadores de número
String.prototype.replaceAll ()
String.prototype.replaceAll () ( cláusula de Mathias Bynens ) permite substituir todas as instâncias de uma substring em uma string por um valor diferente sem usar um regex global.
No exemplo a seguir, substituímos todos os caracteres "+" por vírgulas com um espaço usando uma expressão regular:
const strWithPlus = '++'
const strWithComma = strWithPlus.replace(/+/g, ', ')
// , ,
Essa abordagem requer o uso de uma expressão regular. No entanto, expressões regulares complexas costumam ser uma fonte de erros.
Há outra abordagem baseada no uso dos métodos String.prototype.split () e Array.prototype.join ():
const strWithPlus = '++'
const strWithComma = strWithPlus.split('+').join(', ')
// , ,
Essa abordagem evita o uso de expressões regulares, mas você precisa dividir a string em partes separadas (palavras), convertê-la em uma matriz e, a seguir, concatenar os elementos da matriz em uma nova string.
String.prototype.replaceAll () resolve esses problemas e fornece uma maneira simples e conveniente de substituir substrings globalmente:
const strWithPlus = '++'
const strWithComma = strWithPlus.replaceAll('+', ', ')
// , ,
Observe que, para consistência com APIs anteriores, o comportamento de String.prototype.replaceAll (searchValue, newValue) (searchValue é o valor de pesquisa, newValue é o novo valor) é o mesmo que String.prototype.replace (searchValue, newValue), exceto pelo seguinte:
- Se o valor pesquisado for uma string, então replaceAll substitui todas as correspondências e substitui apenas a primeira
- Se o valor desejado for uma expressão regular não global, então substituir substitui a primeira correspondência, e replaceAll lança uma exceção para evitar um conflito entre a ausência do sinalizador "g" e o nome do método (substituir tudo - substituir todas [correspondências])
Se uma expressão regular global for usada como o valor de pesquisa, então, replace e replaceAll se comportam da mesma forma.
E se tivermos uma linha com um número arbitrário de espaços no início, no final da linha e entre as palavras?
const whiteSpaceHell = ' '
E queremos substituir dois ou mais espaços por um. O replaceAll pode resolver esse problema? Não.
Com String.prototype.trim () e substitua por uma expressão regular global, isso é feito assim:
const whiteSpaceNormal =
whiteSpaceHell
.trim()
.replace(/\s{2,}/g, ' ')
// \s{2,}
//
Promise.any ()
Promise.any () (uma sugestão de Mathias Bynens, Kevin Gibbons e Sergey Rubanov ) retorna o valor da primeira promessa cumprida. Se você rejeitar todas as promessas passadas para Promise.any () como um argumento (como uma matriz), uma exceção "AggregateError" é lançada.
AggregateError é uma nova subclasse de erro que agrupa erros individuais. Cada instância de AggregateError contém uma referência a uma matriz com exceções.
Vamos considerar um exemplo:
const promise1 = new Promise((resolve, reject) => {
const timer = setTimeout(() => {
resolve('p1')
clearTimeout(timer)
}, ~~(Math.random() * 100))
}) // ~~ - Math.floor()
const promise2 = new Promise((resolve, reject) => {
const timer = setTimeout(() => {
resolve('p2')
clearTimeout(timer)
}, ~~(Math.random() * 100))
})
;(async() => {
const result = await Promise.any([promise1, promise2])
console.log(result) // p1 p2
})()
O resultado será o valor da primeira promessa resolvida.
Exemplo da frase:
Promise.any([
fetch('https://v8.dev/').then(() => 'home'),
fetch('https://v8.dev/blog').then(() => 'blog'),
fetch('https://v8.dev/docs').then(() => 'docs')
]).then((first) => {
// ()
console.log(first);
// → 'home'
}).catch((error) => {
//
console.log(error);
})
Observe que Promise.race (), ao contrário de Promise.any (), retorna o valor da primeira promessa resolvida, seja cumprida ou rejeitada.
WeakRefs
WeakRefs (referências fracas) ( proposto por Dean Tribble, Mark Miller, Till Schneidereit, etc. ) fornece dois novos recursos:
- Criando referências fracas para um objeto usando a classe WeakRef
- Executando finalizadores personalizados após a coleta de lixo usando a classe FinalizationRegistry
Resumindo, WeakRef permite criar referências fracas a objetos que são valores de propriedades de outro objeto, e os finalizadores podem ser usados, entre outras coisas, para remover referências a objetos "limpos" pelo coletor de lixo.
Esta técnica pode ser útil ao criar uma função de memorização (memoização) que usa o cache integrado para evitar a execução repetida da função se houver um valor calculado para o argumento passado para a função no cache (desde que os objetos sejam usados como os valores das propriedades do objeto de cache e o risco de sua exclusão subsequente) ...
Como você deve se lembrar, a razão para o surgimento em JavaScript de uma estrutura como Map (tabela hash), além da busca mais rápida por um valor por chave, foi que as chaves de um objeto comum só podem ser strings ou caracteres. O mapa, por outro lado, permite usar qualquer tipo de dado como chave, incluindo objetos.
Porém, logo surgiu um problema de vazamento de memória: a exclusão dos objetos que eram chaves do Mapa não os tornava inacessíveis (marcar e varrer), o que impedia que o coletor de lixo os destruísse, liberando a memória que estavam ocupando.
Em outras palavras, os objetos usados como chaves no Mapa são salvos para sempre.
Outra estrutura, WeakMap (e WeakSet), foi introduzida para resolver esse problema. A diferença entre WeakMap e Map é que as referências a objetos-chave no WeakMap são fracas: a exclusão de tais objetos permite que o coletor de lixo realoque a memória alocada para eles.
Assim, esta proposta representa o próximo estágio no desenvolvimento de uma tabela hash em JavaScript. Os objetos agora podem ser usados como chaves e valores em outros objetos sem o risco de vazamentos de memória.
Mais uma vez, quando se trata de construir um cache embutido:
- Se não houver risco de vazamentos de memória, use o Map
- Ao usar objetos-chave que podem ser excluídos posteriormente, use WeakMap
- Ao usar objetos de valor que podem ser excluídos posteriormente, use Map em conjunto com WeakRef
Um exemplo do último caso da proposta:
function makeWeakCached(f) {
const cache = new Map()
return key => {
const ref = cache.get(key)
if (ref) {
//
const cached = ref.deref()
if (cached !== undefined) return cached;
}
const fresh = f(key)
// ( )
cache.set(key, new WeakRef(fresh))
return fresh
};
}
const getImageCached = makeWeakCached(getImage);
- O construtor WeakRef recebe um argumento que deve ser um objeto e retorna uma referência fraca a ele
- O método deref de uma instância WeakRef retorna um de dois valores:
No caso do cache integrado, o finalizador é projetado para concluir o processo de limpeza após o objeto de valor ser destruído pelo coletor de lixo ou, mais simplesmente, para remover uma referência fraca a tal objeto.
function makeWeakCached(f) {
const cache = new Map()
// -
const cleanup = new FinalizationRegistry(key => {
const ref = cache.get(key)
if (ref && !ref.deref()) cache.delete(key)
})
return key => {
const ref = cache.get(key)
if (ref) {
const cached = ref.deref()
if (cached !== undefined) return cached
}
const fresh = f(key)
cache.set(key, new WeakRef(fresh))
// ( )
cleanup.register(fresh, key)
return fresh
}
}
const getImageCached = makeWeakCached(getImage);
Leia mais sobre finalizadores e como usá-los na proposta. Em geral, use finalizadores apenas quando for absolutamente necessário.
Operadores de atribuição booleana
Operadores booleanos de atribuição ( proposta de Justin Ridgewell e Hemanth HM ) são uma combinação de operadores booleanos (&&, ||, ??) e expressões de atribuição.
A partir de hoje, o JavaScript tem os seguintes operadores de atribuição:
=
+=
-=
/=
*=
&&=
||=
??=
(null undefined - , 0, false, '' - )
**=
%=
&=
|=
^=
<<=
>>=
>>>=
[a, b] = [ 10, 20 ]
{a, b} = { a: 10, b: 20 }
A cláusula permite combinar operadores lógicos e expressões de atribuição:
a ||= b
// : a || (a = b)
// , "a"
a &&= b
// : a && (a = b)
// , "a"
a ??= b
// : a ?? (a = b)
// , "a" (null undefined)
Exemplo da frase:
//
function example(opts) {
// ,
opts.foo = opts.foo ?? 'bar'
// ,
opts.baz ?? (opts.baz = 'qux')
}
example({ foo: 'foo' })
//
function example(opts) {
//
opts.foo ??= 'bar'
// "" opts.baz
opts.baz ??= 'qux';
}
example({ foo: 'foo' })
Separadores de número
Separadores de números ( sugestão de Christophe Porteneuve ), ou mais especificamente, separadores de números em números, permitem adicionar um sublinhado (_) entre os números para torná-los mais legíveis.
Por exemplo:
const num = 100000000
// num? 1 ? 100 ? 10 ?
Os separadores resolvem este problema:
const num = 100_000_000 // : 100
Os separadores podem ser usados nas partes inteiras e decimais de um número:
const num = 1_000_000.123_456
Os separadores podem ser usados não apenas em números inteiros e de ponto flutuante, mas também em literais binários, hexadecimais, octais e BigInt.
O desenvolvimento posterior de separadores de número implica a possibilidade de uso útil de vários separadores consecutivos e separadores que vêm antes e depois do número.
Quer testar ou aprimorar seus conhecimentos de JavaScript? Então preste atenção na minha aplicação maravilhosa (você não pode se elogiar ...).
Espero que você tenha encontrado algo interessante para você. Obrigado pela atenção.