我不曾見過的 JS 特性

我不曾見過的 JS 特性

有一天我正在閱讀 MDN 文檔,發現了一些我以前壓根沒有意識到在 JS 中存在的特性和 API。這裏我羅列了一些,無論它們是否有用,JS 的學習永無止境。前端

標記語句

有多少人知道在 JS 裏你能夠給 for 循環和語句塊命名?反正我不知道…… 命名完新名稱以後你能夠在 for 循環中的 breakcontinue 以後、語句塊中的 break 以後使用新名稱。android

loop1: // 標記 "loop1" 
for (let i = 0; i < 3; i++) { // "loop1"
   loop2: // 標記 "loop2"
   for (let j = 0; j < 3; j++) { // "loop2"
      if (i === 1) {
         continue loop1; // 繼續外層的 "loop1" 循環
         // break loop1; // 停止外層的 "loop1" 循環
      }
      console.log(`i = ${i}, j = ${j}`);
   }
}

/* 
 * # 輸出
 * i = 0, j = 0
 * i = 0, j = 1
 * i = 0, j = 2
 * i = 2, j = 0
 * i = 2, j = 1
 * i = 2, j = 2
 */
複製代碼

下面是語句塊命名的例子,在語句塊中你只能在 break 以後使用新命名。ios

foo: {
  console.log('one');
  break foo;
  console.log('這句打印不會被執行');
}
console.log('two');

/*
 * # 輸出
 * one
 * two
 */
複製代碼

"void" 運算符

我一度覺得我已經瞭解了全部的運算符,直到我看到了這一個。它從 1996 年 起就存在於 JS 了。全部的瀏覽器都支持,而且它也很容易理解,引用自 MDN:git

void 運算符對給定的表達式進行求值,而後返回 undefined。github

使用它,你能夠換一種方式來寫當即調用的函數表達式(IIFE),就像這樣:後端

void function iife() {
	console.log('hello');
}();

// 和下面等效

(function iife() {
    console.log('hello');
})()
複製代碼

使用 void 的一個注意點是,不管給定的表達式返回結果是什麼,void 運算符的總體結果都是空的(undefined)!瀏覽器

const word = void function iife() {
	return 'hello';
}();

// word 是 `undefined`

const word = (function iife() {
	return 'hello';
})();

// word 是 "hello"
複製代碼

你也能夠和 async 一塊兒使用 void,這樣你就能把函數做爲異步代碼的入口:bash

void async function() { 
    try {
        const response = await fetch('air.ghost.io'); 
        const text = await response.text();
        console.log(text);
    } catch(e) {
        console.error(e);
    }
}()

// 或者保持下面的寫法

(async () => {
    try {
        const response = await fetch('air.ghost.io'); 
        const text = await response.text();
        console.log(text);
    } catch(e) {
        console.error(e);
    }
})();
複製代碼

逗號運算符

在學習了逗號運算符以後,我意識到了以前我並不徹底清楚其工做原理。下面是來自 MDN 的引用:babel

逗號運算符對它的每一個操做數求值(從左到右),並返回最後一個操做數的值。異步

function myFunc() {
  let x = 0;
  return (x += 1, x); // 等價於 return ++x;
}

y = false, true; // console 中獲得 true
console.log(y); // false,逗號優先級低於賦值

z = (false, true); // console 中獲得 true
console.log(z); // true,括號中總體返回 true
複製代碼

配合 條件運算符

逗號運算符中的最後一個值做爲返回給條件運算符的值,所以你能夠在最後一個值前面聽任意多個表達式。在下面的例子中,我在返回的布爾值以前放了打印語句。

const type = 'man';

const isMale = type === 'man' ? (
    console.log('Hi Man!'),
    true
) : (
    console.log('Hi Lady!'),
    false
);

console.log(`isMale is "${isMale}"`);
複製代碼

國際化 API

即便在最有利的狀況下,國際化仍是很難作好。幸虧還有一套大部分瀏覽器都支持得不錯的 API。其中我最愛的一個特性就是日期格式化,見下面的例子:

const date = new Date();

const options = {
  year: 'numeric', 
  month: 'long', 
  day: 'numeric'
};

const formatter1 = new Intl.DateTimeFormat('es-es', options);
console.log(formatter1.format(date)); // 22 de diciembre de 2017

const formatter2 = new Intl.DateTimeFormat('en-us', options);
console.log(formatter2.format(date)); // December 22, 2017
複製代碼

管道操做符

在此篇成文之時,該功能只有 Firefox 58 及以上版本經過傳入啓動參數來支持,不過 Babel 已經有一個針對它的 插件提議。它看起來應該是受到 bash 的啓發,我以爲很棒!

const square = (n) => n * n;
const increment = (n) => n + 1;

// 不使用管道操做符
square(increment(square(2))); // 25

// 使用管道操做符
2 |> square |> increment |> square; // 25
複製代碼

值得一提

Atomics

當數據被多個線程共享時,原子操做確保正在讀和寫的數據是符合預期的,即下一個原子操做必定會在上一個原子操做結束以後纔會開始。這有利於保持不一樣線程間的數據同步(好比主線程和另外一條 WebWorker 線程)。

我很喜歡如 Java 等其它語言中的原子性。我預感當愈來愈多的人使用 WebWorkers,將操做從主線程分離出來時,原子操做的使用會愈來愈普遍。

Array.prototype.reduceRight

好吧,我以前從未見過這個,由於它基本等同於 Array.prototype.reduce() + Array.prototype.reverse() 而且你不多須要這麼作。但若是你有這需求的話,reduceRight 是最好的選擇!

const flattened = [[0, 1], [2, 3], [4, 5]].reduceRight(function(a, b) {
    return a.concat(b);
}, []);

// flattened array is [4, 5, 2, 3, 0, 1]
複製代碼

setTimeout() 參數

這個早就存在了,但若是我早點知道的話,我大概能夠省去不少的 .bind(...)

setTimeout(alert, 1000, 'Hello world!');

/*
 * # alert 輸出
 * Hello World!
 */

function log(text, textTwo) {
    console.log(text, textTwo);
}

setTimeout(log, 1000, 'Hello World!', 'And Mars!');

/*
 * # 輸出
 * Hello World! And Mars!
 */
複製代碼

HTMLElement.dataset

在此以前我一直對 HTML 元素使用自定義數據屬性 data-*,由於我未曾意識到存在一個 API 來方便地查詢它們。除了個別的命名限制以外(見上面的連接),它的做用基本就是在 JS 中查詢的時候容許你使用駝峯命名法(camelCase)來查詢「減號-命名」(dash-case)的屬性。因此屬性名 data-birth-planet 在 JS 中就變成了 birthPlanet

<div id='person' data-name='john' data-birth-planet='earth'></div>
複製代碼

查詢:

let personEl = document.querySelector('#person');

console.log(personEl.dataset) // DOMStringMap {name: "john", birthPlanet: "earth"}
console.log(personEl.dataset.name) // john
console.log(personEl.dataset.birthPlanet) // earth

// 你也能夠在程序中添加屬性
personEl.dataset.foo = 'bar';
console.log(personEl.dataset.foo); // bar
複製代碼

結束語

我但願你和我同樣在這裏學到了一些新知識。在此也贊一下 Mozila 新的 MDN 站點,看起來很是棒,我花了比想象中更多的時間來閱讀文檔。

修訂: 修正幾處命名而且爲 async 函數添加 try, catch。感謝 Reddit!

2018 新年快樂!


掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章
相關標籤/搜索