Coisas de JavaScript que eu nunca tinha ouvido falar

Postado em: 31/01/2018

Atualizado em: 31/01/2018

O post de hoje é uma tradução de um artigo que vi uns dias atrás, de autoria do Nick, e achei muito legal, por isso achei que seria interessante compartilhá-lo com vocês aqui no blog. Pra quem deita e rola no inglês, pode conferir o artigo original aqui.

Para quem não tem uma boa afinidade com a língua, segue o artigo traduzido logo abaixo:
Logo HTML5 com o nome IndexedDB em seguida

Estava lendo o MDN docs outro dia e descobri essas features e APIs JavaScript que eu nunca tinha ouvido falar. Então aqui está uma pequena lista dessas coisas, útil ou não – aprender JS parece uma coisa que nunca tem fim.

Label Statements

Você pode rotular blocos e loops for em javascript. Quem sabia? (Eu não!) Você pode pegar a referência à esses rótulos e usar break e continue nos loops for, e break em blocos.

        
  1. loop1: // rotulando "loop1"
  2. for (let i = 0; i < 3; i++) { // "loop1"
  3. loop2: // rotulando "loop2"
  4. for (let j = 0; j < 3; j++) { // "loop2"
  5. if (i === 1) {
  6. continue loop1; // continue no "loop1"
  7. // break loop1; // sai do "loop1"
  8. }
  9. console.log(`i = ${i}, j = ${j}`);
  10. }
  11. }
  12. /*
  13. * # Output
  14. * i = 0, j = 0
  15. * i = 0, j = 1
  16. * i = 0, j = 2
  17. * i = 2, j = 0
  18. * i = 2, j = 1
  19. * i = 2, j = 2
  20. */

Aqui vai um exemplo nomeando um bloco, você pode usar apenas break em blocos.

        
  1. foo: {
  2. console.log('um');
  3. break foo;
  4. console.log('esse log não será executado');
  5. }
  6. console.log('dois');
  7. /*
  8. * # Output
  9. * um
  10. * dois
  11. */

Operador “void”

Eu pensei que sabia todos os operadores, até que eu vi um que está presente no Javascript desde 1996. Ele é suportado por todos os navegadores e é bem fácil de entender. Veja um trecho retirado do MDN:

O operador void avalia a expressão e depois retorna undefined.

Isso nos permite escrever um IIFE alternativo como esse:

        
  1. void function iife() {
  2. console.log('hello');
  3. }();
  4. // é o mesmo que ...
  5. (function iife() {
  6. console.log('hello');
  7. })();

Uma coisa ruim com void é o fato de o retorno da função ser undefined.

        
  1. const word = void function iife() {
  2. return 'hello';
  3. }();
  4. // word é "undefined"
  5. const word = (function iife() {
  6. return 'hello';
  7. })();
  8. // word é "hello"

Você também pode usar void com async, utilizando como um ponto de entrada assíncrono para o seu código:

        
  1. void async function() {
  2. try {
  3. const response = await fetch('air.ghost.io');
  4. const text = await response.text();
  5. console.log(text);
  6. } catch(e) {
  7. console.error(e);
  8. }
  9. }();
  10. // ou faça apenas assim :)
  11. (async () => {
  12. try {
  13. const response = await fetch('air.ghost.io');
  14. const text = await response.text();
  15. console.log(text);
  16. } catch(e) {
  17. console.error(e);
  18. }
  19. })();

Operador de vírgula

Depois de ler sobre o operador de vírgula, eu percebi que eu não estava totalmente ciente de como o mesmo funcionava. Veja um ótimo trecho retirado do MDN:

O operador de vírgula avalia cada um de seus operandos(da esqueda para a direita) e retorna o valor de seu último operando.

        
  1. function myFunc() {
  2. let x = 0;
  3. return (x += 1, x); // mesmo que return ++x;
  4. }
  5. y = false, true; // retorna true no console
  6. console.log(y); // false (mais à esquerda)
  7. z = (false, true); // retorna true no console
  8. console.log(z); // true (mais à direita)

Usando operador condicional

O último valor no operador de vírgula será o valor retornado para a condicional. Então você pode colocar qualquer número de expressões antes. No exemplo abaixo eu coloco um console log antes de retornar um booleano.

        
  1. const type = 'man';
  2. const isMale = type === 'man' ? (
  3. console.log('Hi Man!'),
  4. true
  5. ) : (
  6. console.log('Hi Lady!'),
  7. false
  8. );
  9. console.log(`isMale is "${isMale}"`);

API de Internacionalização

A Internacionalização era uma coisa difícil de se trabalhar há pouco tempo atrás, felizmente existe uma API com bom suporte atualmente na maioria dos navegadores. Uma das minhas features favoritas é o formatador de datas. Veja o exemplo abaixo.

        
  1. const date = new Date();
  2. const options = {
  3. year: 'numeric',
  4. month: 'long',
  5. day: 'numeric'
  6. };
  7. const formatter1 = new Intl.DateTimeFormat('es-es', options);
  8. console.log(formatter1.format(date)); // 22 de diciembre de 2017
  9. const formatter2 = new Intl.DateTimeFormat('en-us', options);
  10. console.log(formatter2.format(date)); // December 22, 2017

Pipeline operator

No momento em que eu estava escrevendo este artigo, o operador pipeline só tinha suporte no Firefox 58+ com uma flag, entretanto, o Babel tem um plugin para lidar com essa situação. Eu gosto bastante desse.

        
  1. const square = (n) => n * n;
  2. const increment = (n) => n + 1;
  3. // sem pipeline operator
  4. square(increment(square(2))); // 25
  5. // com pipeline operator
  6. 2 |> square |> increment |> square; // 25

Menções importantes

Atômicos

Operações atômicas nos permite leitura e escrita previsíveis de valores quando os dados são compartilhados entre múltiplas threads, esperando que outras operações encerrem antes que a próxima seja executada. Operações atômicas são bastante úteis para manter dados síncronos entre coisas como a thread principal e outro WebWorker.

Eu gosto bastante disso em outras linguagens, como Java. Eu sinto que elas serão mais usadas em JS quando a maioria dos programadores começarem a usar WebWorkers para tirar operações da thread principal.

Array.prototype.reduceRight

Ok, eu nunca tinha usado este porque é basicamente Array.prototype.reduce() + Array.prototype.reverse() e é bem difícil que você precise dessa combinação. Mas, se você precisar, ReduceRight é perfeito para você!

        
  1. const achatado = [[0, 1], [2, 3], [4, 5]].reduceRight(function(a, b) {
  2. return a.concat(b);
  3. }, []);
  4. // o array achatado é [4, 5, 2, 3, 0, 1]

Parâmetros do setTimeOut()

Eu provavelmente teria me poupado de um .bind(…) ou dois por saber disso - agora tem sido assim.

        
  1. setTimeout(alert, 1000, 'Hello world!');
  2. /*
  3. * # Output (alert)
  4. * Hello World!
  5. */
  6. function log(text, textTwo) {
  7. console.log(text, textTwo);
  8. }
  9. setTimeout(log, 1000, 'Hello World!', 'And Mars!');
  10. /*
  11. * # Output
  12. * Hello World! And Mars!
  13. */

HTMLElement.dataset

Eu sempre usei data attributes personalizados (data -*) nos elementos HTML, mas, infelizmente, eu não estava ciente que havia uma API para consultá-los facilmente, até agora. Além de algumas restrições de nomenclarura (ver este link) a api é basicamente dash-case para atributos e camelCase quando forem consultados no JS. Então o atributo data-birth-planet seria birthPlanet em JavaScript.

        
  1. <div id='person' data-name='john' data-birth-planet='earth'></div>

Query:

        
  1. let personEl = document.querySelector('#person');
  2. console.log(personEl.dataset) // DOMStringMap {name: "john", birthPlanet: "earth"}
  3. console.log(personEl.dataset.name) // john
  4. console.log(personEl.dataset.birthPlanet) // earth
  5. // Você pode adicionar mais se quiser
  6. personEl.dataset.foo = 'bar';
  7. console.log(personEl.dataset.foo); // bar

Fim

Espero que você tenha descoberto algo novo de JavaScript assim como eu. Parabéns ao Mozilla pelo novo site do MDN, está muito melhor, na minha opinião – Eu passei muito mais tempo lendo nele do que eu pensava que iria.

Feliz 2018!