- 原文地址:JS things I never knew existed
- 原文作者:Skyllo
- 譯文出自:掘金翻譯計劃
- 本文永久連結:github.com/xitu/gold-m…
- 譯者:Yong Li
- 校對者:Yukiko,dz
我未曾見過的 JS 特性
有一天我正在閱讀 MDN 文件,發現了一些我之前壓根沒有意識到在 JS 中存在的特性和 API。這裡我羅列了一些,不管它們是否有用,JS 的學習永無止境。
標記語句
有多少人知道在 JS 裡你可以給 for
迴圈和語句塊命名?反正我不知道…… 命名完新名稱之後你可以在 for
迴圈中的 break
和 continue
之後、語句塊中的 break
之後使用新名稱。
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
之後使用新命名。
foo: {
console.log('one');
break foo;
console.log('這句列印不會被執行');
}
console.log('two');
/*
* # 輸出
* one
* two
*/
複製程式碼
"void" 運算子
我一度以為我已經瞭解了所有的運算子,直到我看到了這一個。它從 1996 年 起就存在於 JS 了。所有的瀏覽器都支援,並且它也很容易理解,引用自 MDN:
void 運算子對給定的表示式進行求值,然後返回 undefined。
使用它,你可以換一種方式來寫立即呼叫的函式表示式(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
,這樣你就能把函式作為非同步程式碼的入口:
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 的引用:
逗號運算子對它的每個運算元求值(從左到右),並返回最後一個運算元的值。
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 新年快樂!
掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。