我是阿傑,上一篇說到我為了犒賞自己跑去買了 唉噁怕死普羅,但我並沒有亂花錢,我只是讓它變成了我想要的形狀!
陣列也可以,只要你會用 fill()
,你可以將它的內容變成各種型別的值,甚至是二維陣列,只是被替換的內容跟錢錢不一樣,它是真的不見了XD!
我們會分成以下幾個部分介紹:
當你想要把一個陣列的內容用 固定的值 去替換時。
這個值可以是任意型別的值,可以指定一個區間。
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
,將會是陣列的長度回傳被更動元素後的陣列,也就是原陣列。
會改動到原陣列。
fill()
會替換陣列中指定區間的元素,可以用任何型別的值取代,但使用物件型別要注意參照問題,可參考注意事項。
索引 (start
、end
) 可以使用正負數或小數,沒有指定的話就會從 0 開始到陣列結尾 (array.length
),細節可以參考參數的說明。
跟有些咩色不一樣的是,fill()
可以處理稀疏陣列 (sparse array) 的 empty slot,例如:
const array = Array(3).fill(0)
console.log(array)
// [0, 0, 0]
fill()
是一個會變動到原陣列的咩色,它會變動原陣列的內容而非長度。
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]
注意每次都會改動到原陣列。
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]
注意每次都會改動到原陣列。
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()
傳入的 start
或 end
也可以是小數,其轉換的方式不是單純使用 floor()
,請參考注意事項說明的部分。
const array1 = Array(3).fill({})
console.log(array1)
// [{}, {}, {}]
const array2 = Array(3).fill([])
console.log(array2)
// [[], [], []]
利用 Array()
創造一個包含 3 個 empty slot 的空陣列,再使用 fill
取代每個元素。
fill()
傳入的 start
或 end
可以是一個小數,它們會被轉換成一個整數,但請注意其轉換的方式,可參考 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'}]
Array.prototype.fill(value[,start[,end]])
some()
的演算法並沒有要求呼叫它的一定要是一個陣列,可以從步驟 1 跟 Note 3 得知,為了方便解釋,這邊一律使用陣列來說明。
演算法的前 2 個步驟是用來做一些前置處理,包括轉型、確認長度。
步驟 3 蠻值得注意的,這個 ToIntegerOrInfinity
讓 index
是小數仍然可以正常使用,而且因為它在轉換的過程使用了絕對值,導致轉成整數的結果可能會跟預期的不一樣,可以參考 Example 3
在步驟 4 跟步驟 8 可以發現我們可以在 start
跟 end
參數丟入無限小的值 (-♾️), 但都會被轉成 0, 我們來驗證一下:
可以看到步驟 6 跟步驟 9,會將負數的 start
或 end
加上陣列的長度,如果還是小於 0,則使用 0,這讓我們可以使用負數計算起始值,驗證了上面參數的說明。
步驟 3 到步驟 10 確立了 fill()
將要替換的區間,步驟 11 則開始執行替換。
出現 ?
的地方代表有可能會丟出錯誤,所以整個演算法有 5 處有機會丟出錯誤,例如步驟 3 的 ToIntegerOrInfinity()
,當你傳入 Symbol 或 BigInt,即會從內部的 ToNumber()
丟出一個 TypeError 的錯誤,我們來驗證一下:
如果出現 !
,則代表這個 abstract operation 絕對不會丟出錯誤,例如步驟 11 的 ToString()
它會在參數是一個 Symbol 時丟出一個 TypeError,但我們確定丟進去的是一個 Number (F(k)
),因此不會有丟出錯誤的可能。
從 ECMAScript 的演算法來看,尚未找到與 JavaScript 實作的不同之處。
JavaScript 不像其他語言 (例如 Python) 有支援從陣列結尾計算索引,但有些咩色會提供這個功能,讓我們可以在參數中使用負值索引,很多時候看起來會直覺許多。
最後,希望大家可以開心地使用各種咩色,體驗它帶給你的便利,祝大家歸剛沒煩惱。