點燈坊

失くすものさえない今が強くなるチャンスよ

使用 generate() 產生 Sequence

Sam Xiao's Avatar 2019-10-16

若我們想指定特定長度建立 Array,且給定初始值,隨後會自動建立 Sequence,在 ECMAScript 並沒有內建 Function,但我們可以自行建立 generate() 完成需求。

Version

macOS Catalina 10.15
VS Code 1.39.1
Quokka 1.0.256
ECMAScript 2015
Ramda 0.26.1
Wink-fp 0.1.11

Array.prototype.map()

let generate = n => begin => Array(n).map((_, i) => i + begin);

generate(3)(1); // ?

直覺會使用 Array(n) 先建立 length 為 n 的 array,再使用 map() 建立 sequence。

generate000

但結果會發現不如預期。

因為 new Array(n) 會建立 length 為 n 的 sparse array,也就是內容為 hole。

map() 會 skip 這些 hole 但保留之,因此回傳原本 array。

Function.prototype.apply()

Array.apply(null, Array(3));

改用 Array.apply() 呼叫 Array(),也就是 Array.apply(null, [1, 2]) 相當於 Array(1, 2)

Array.apply() 有個特殊功能:將 hole 視為 undefined 處理,因此 Array.apply(null, Array(3)) 將回傳 [undefined, undefined, undefined]

generate001

let generate = n => begin => Array.apply(null, Array(n)).map((_, i) => i + begin);

generate(3)(1); // ?  

也因為 Array.apply(null, Array(n)) 不再是 length 為 n 的 empty array,因此可繼續使用 map() 建立 sequence。

generate002

Array.from()

let generate = n => begin => Array.from({ length: n }, (_, i) => i + begin);

generate(3)(2); // ?

Array.from() 原本設計讓你以 map() 方式處理 array-like object。

documents 就是典型 array-like object,帶有 length property

因此我們可使用 { length: n } 代表 Array(n),且沒有 empty array 與 hole 問題。

Array.from() 的第二個 argument 為 function,如同 map() 用法。

generate003

Conclusion

  • Array.apply() 巧妙地將 hole 視為 undefined,因此可繼續使用 map()
  • ES6 的 Array.from() 是很強大 function,可以實作出很多有趣功能
  • Array.from() 相當於 Array()map() 合體,還可避開 empty array

Reference

MDN, Array.from()
Dr.Axel Rauschdayer, Array iteration and holes in JavaScript