點燈坊

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

使用 create() 依特定長度與初始值建立 Array

Sam Xiao's Avatar 2019-10-13

若我們想指定特定長度建立 Array,且初始值都相同,在 ECMAScript 並沒有內建 Function,但我們可以自行建立 create() 完成需求。

Version

macOS Catalina 10.15
VS Code 1.39.1
Quokka 1.0.254
Ramda 0.26.1
Wink-fp 0.1.9

Array.prototype.map()

let create = n => init => Array(n).map(() => init);

create(3)(1); // ?

直覺會使用 Array(n) 先建立 length 為 n 的 array,再使用 map() 設定初始值。

create000

但結果會發現不如預期。

因為 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]

create001

let create = n => init => Array.apply(null, Array(n)).map(() => init);

create(3)(1); // ?  

也因為 Array.apply(null, Array(n)) 不再是 length 為 n 的 sparse array,因此可繼續使用 map() 設定初始值。

create002

Array.from()

let create = n => init => Array.from({ length : n }, () => init);

create(3)(1); // ?

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

documents 就是典型 array-like object,帶有 length property;而 String、Set、Map 是典型 iterable object,可使用 for of

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

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

create003

Wink-fp

import { create } from 'wink-fp';

create(3)(1); // ?

Wink-fp 已經內建 create(),可直接使用。

create()
Number -> a -> [a]
依特定長度與初始值建立 array

Number:特定長度

a:Array 的初始值

[a]:回傳新的 array

create004

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
Dr.Axel Rauschdayer, Initializing an array with values