[譯]JS裡我才知道的東西

zhangbao90s發表於2019-07-04

我告訴大家一個寫作心得,文章是靠改的。我的文章通常要改六七次,看上去像一氣呵成,其實花費很多精力。

—— 《木心專訪》

譯文原鏈:air.ghost.io/js-things-i…

導讀:2017年底,本文作者 Nick 通讀了 MDN 文件,發現了一些之前不知道的 JS 特性和 API,於是寫了一篇簡短的小文。作者說:“這份簡短的清單,對你可能並沒有用,卻闡釋了 JS 學習之路永無止境的道理”。

注:文章翻譯時,有刪改。

Label 語句

在 JS 裡可以為 for 迴圈和程式碼塊標記名稱。在 for 迴圈內部,可以使用 breakcontinue 指向此標記名稱;而在程式碼塊中,只能使用 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('第一條 log');
  break foo;
  console.log('這條 log 不會被列印出來的');
}
console.log('第二條 log');

/*
輸出:

第一條 log
第二條 log
*/
複製程式碼

void 操作符

作者在閱讀 JS since 1996 的時候,知道了 void 操作符,受到所有瀏覽器的支援,MDN 的解釋是:

void 操作符會計算後面給定的表示式,然後返回 undefined

這樣我們就多了 IIFE 的另一種寫法:

void function iife() {
    console.log('你好啊');
}();

// 跟下面是一樣的

(function iife() {
    console.log('你好~');
})()
複製程式碼

void 操作符不管後面表示式的計算結果如何,總是返回 undefined

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

// word 的值是 `undefined`

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

// 這裡 word 的值是 `'hello'`
複製程式碼

void 還可與 async 結合使用,可以使用它作為非同步程式碼入口點。

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;
}
console.log(myFunc()) // 1

y = false, true; // 這條語句的執行結果是 true
console.log(y); // y 的值是 false

z = (false, true); // 等號右側表示式的值是 true
console.log(z); // z 的值是 true

/*
輸出:

1
false
true
*/
複製程式碼

與條件/三目操作符結合使用

逗號運算子表示式總是返回最後一個值,因此在條件運算子的判斷中,我們可以在最後一個值之前新增任意數量的表示式。在下面的例子中,我們在返回布林值之前,放了一個 console log 在前面。

const type = 'man';

const isMale = type === 'man' ? (
    console.log('嗨,先生們!'),
    true
) : (
    console.log('嗨,女士們!'),
    false
);

console.log(`isMale 的值是 "${isMale}"`);

/*
輸出:

嗨,先生們!
isMale 的值是 "true"
*/
複製程式碼

Internationalization API

國際化 API 現在已經得到很好的支援了,我最喜歡的特性之一就是格式化時間的 DateTimeFormat 了。

const date = new Date();

const options = {
  year: 'numeric', 
  month: 'long', 
  day: '2-digit',
  hour: '2-digit',
  minute: '2-digit',
  second: '2-digit',
  hour12: false
};

const formatter1 = new Intl.DateTimeFormat('zh-CN', { ...options, timeZone: 'Asia/Shanghai' });
console.log(formatter1.format(date));

const formatter2 = new Intl.DateTimeFormat('en-US', { ...options, timeZone: 'America/New_York' });
console.log(formatter2.format(date));

/*
輸出:

2019年7月04日 10:26:03
July 03, 2019, 22:26:03
*/
複製程式碼

Array.prototype.reduceRight

這個方法相當於是 Array.prototype.reverse() + Array.prototype.reduce() 的集合體。從右向左 reduce 陣列。

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

// 扁平化後的 `array` (即 flattened)的值為 [4, 5, 2, 3, 0, 1]
複製程式碼

setTimeout() 的引數

setTimeout 方法用於定時執行一段函式,方法的第一個引數指定觸發函式執行的時間間隔(單位:毫秒)。

在呼叫函式時,我們可能會預先為要執行的函式,先指定前幾個引數,你可能會感覺要使用 .bind(...) 方法實現此功能。然而我們不需要這麼做。

setTimeout 方法第二個往後的引數會在呼叫函式時,會作為引數在函式上使用的。

setTimeout(alert, 1000, '你好,世界!');

/*
輸出:(alert)

你好,世界!
*/

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

setTimeout(log, 1000, '你好,世界!', '還有火星!');

/*
輸出:

你好,世界! 還有火星!
*/
複製程式碼

HTMLElement.dataset

這是查詢 HTML 自定義屬性 data-* 的時候用到一個很方便的 API。不過有一些命名限制,大家知道 HTML 屬性是不區分大小寫的,自定義屬性的命名方式採用 dash-case 的形式,而在 JS 裡查詢時,則是使用對應的 camelCase 形式(忽略 data-* 字首)。比如 data-birth-planet 在 JS 訪問使用的是 birthPlanet

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

現在用 JS 查詢:

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
// 刪除自定義屬性
delete personEl.dataset.foo
複製程式碼

(完)

相關文章