iT邦幫忙

2022 iThome 鐵人賽

DAY 15
0
Modern Web

咩色用得好,歸剛沒煩惱 - 從 ECMAScript 偷窺 JavaScript Array method系列 第 15

Day15 咩色用得好 - Array.prototype.fill (將陣列變成你想要的形狀)

  • 分享至 

  • xImage
  •  

Abstract

我是阿傑,上一篇說到我為了犒賞自己跑去買了 唉噁怕死普羅,但我並沒有亂花錢,我只是讓它變成了我想要的形狀!

15.4

陣列也可以,只要你會用 fill(),你可以將它的內容變成各種型別的值,甚至是二維陣列,只是被替換的內容跟錢錢不一樣,它是真的不見了XD!

我們會分成以下幾個部分介紹:

  • 使用時機
  • 語法
  • 說明
  • 範例
  • 注意事項
  • ECMAScript
  • 結論

使用時機

當你想要把一個陣列的內容用 固定的值 去替換時。

這個值可以是任意型別的值,可以指定一個區間。


語法

fill(value)
fill(value, start)
fill(value, start, end)

參數

第 1 個參數為 value
第 2 個參數為 start (可選的)
第 3 個參數為 end (可選的)

value

這個值會用來取代陣列中指定區間的元素,可以是任一型別的值。

start (optional)

指定替換區間的起始點 (包含本身)。

型別應該為 1 個數字,可以是小數。

  • 如果為正數,會從陣列開始的地方算起
  • 如果為負數,則會從陣列結尾的地方算起 (array.length + start)
  • 如果沒有提供 start,將會從 0 開始

end (optional)

指定替換區間的結束點 (不包含本身)。

型別應該為 1 個數字,可以是小數。

  • 如果為正數,會從陣列開始的地方算起
  • 如果為負數,則會從陣列結尾的地方算起 (array.length + start)
  • 如果沒有提供 end,將會是陣列的長度

Return

回傳被更動元素後的陣列,也就是原陣列。

Mutability

會改動到原陣列。


說明

fill() 會替換陣列中指定區間的元素,可以用任何型別的值取代,但使用物件型別要注意參照問題,可參考注意事項。

索引 (startend) 可以使用正負數或小數,沒有指定的話就會從 0 開始到陣列結尾 (array.length),細節可以參考參數的說明。

跟有些咩色不一樣的是,fill() 可以處理稀疏陣列 (sparse array) 的 empty slot,例如:

const array = Array(3).fill(0)

console.log(array)
// [0, 0, 0]

fill() 是一個會變動到原陣列的咩色,它會變動原陣列的內容而非長度。


範例

Example 1 - 基礎用法

const numbers = [0, 0, 0, 0, 0]
numbers.fill(1)
console.log(numbers)
// [1, 1, 1, 1, 1]

numbers.fill(2, 2)
console.log(numbers)
// [1, 1, 2, 2, 2]

numbers.fill(3, 1, 4)
console.log(numbers)
// [1, 3, 3, 3, 2]

注意每次都會改動到原陣列。

Example 2 - 索引超出範圍

const numbers = [0, 0, 0, 0]

numbers.fill(1, 4)
console.log(numbers)
// [0, 0, 0, 0]

numbers.fill(1, -5)
console.log(numbers)
// [1, 1, 1, 1]

numbers.fill(2, 0, 6)
console.log(numbers)
// [2, 2, 2, 2]

numbers.fill(1, 0, -6)
// [2, 2, 2, 2]

注意每次都會改動到原陣列。

Example 3 - 使用小數

const numbers = [0, 0, 0, 0]
numbers.fill(1, 1.2)
console.log(numbers)
// [0, 1, 1, 1]

numbers.fill(2, 2.7)
console.log(numbers)
// [0, 1, 2, 2]

numbers.fill(3, 0.1, -2.8)
console.log(numbers)
// [3, 3, 2, 2]

fill() 傳入的 startend 也可以是小數,其轉換的方式不是單純使用 floor(),請參考注意事項說明的部分。

Example 4 - 填充物件類型的值

const array1 = Array(3).fill({})
console.log(array1)
// [{}, {}, {}]

const array2 = Array(3).fill([])
console.log(array2)
// [[], [], []]

利用 Array() 創造一個包含 3 個 empty slot 的空陣列,再使用 fill
取代每個元素。


注意事項

fill() 傳入的 startend 可以是一個小數,它們會被轉換成一個整數,但請注意其轉換的方式,可參考 ToIntegerOrInfinity 這個 abstract operation 跟範例的 Example 3。

務必注意當第 1 個參數 (value) 為物件型別的值時,fill() 所替換的每一個元素都會是同一個參照 (reference),也就是說這些元素都會指向同一個物件,例如以下:

const array = Array(3).fill({})

console.log(array)
// [{}, {}, {}]

array[0].name = 'Alejo'
console.log(array)
// [{name: 'Alejo'}, {name: 'Alejo'}, {name: 'Alejo'}]

ECMAScript

15.1

some() 的演算法並沒有要求呼叫它的一定要是一個陣列,可以從步驟 1 跟 Note 3 得知,為了方便解釋,這邊一律使用陣列來說明。

演算法的前 2 個步驟是用來做一些前置處理,包括轉型、確認長度。

步驟 3 蠻值得注意的,這個 ToIntegerOrInfinity 讓 index 是小數仍然可以正常使用,而且因為它在轉換的過程使用了絕對值,導致轉成整數的結果可能會跟預期的不一樣,可以參考 Example 3

在步驟 4 跟步驟 8 可以發現我們可以在 startend 參數丟入無限小的值 (-♾️), 但都會被轉成 0, 我們來驗證一下:

15.2

可以看到步驟 6 跟步驟 9,會將負數的 startend 加上陣列的長度,如果還是小於 0,則使用 0,這讓我們可以使用負數計算起始值,驗證了上面參數的說明。

步驟 3 到步驟 10 確立了 fill() 將要替換的區間,步驟 11 則開始執行替換。

出現 ? 的地方代表有可能會丟出錯誤,所以整個演算法有 5 處有機會丟出錯誤,例如步驟 3 的 ToIntegerOrInfinity(),當你傳入 Symbol 或 BigInt,即會從內部的 ToNumber()丟出一個 TypeError 的錯誤,我們來驗證一下:

15.3

如果出現 ! ,則代表這個 abstract operation 絕對不會丟出錯誤,例如步驟 11 的 ToString() 它會在參數是一個 Symbol 時丟出一個 TypeError,但我們確定丟進去的是一個 Number (F(k)),因此不會有丟出錯誤的可能。

從 ECMAScript 的演算法來看,尚未找到與 JavaScript 實作的不同之處。


結論

JavaScript 不像其他語言 (例如 Python) 有支援從陣列結尾計算索引,但有些咩色會提供這個功能,讓我們可以在參數中使用負值索引,很多時候看起來會直覺許多。

最後,希望大家可以開心地使用各種咩色,體驗它帶給你的便利,祝大家歸剛沒煩惱。


參考資源


上一篇
Day14 咩色用得好 - Array.prototype.some (沒事沒事,有就好了)
下一篇
Day16 咩色用得好 - Array.prototype.indexOf
系列文
咩色用得好,歸剛沒煩惱 - 從 ECMAScript 偷窺 JavaScript Array method30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言