我是阿傑,由於 splice()
這個咩色的 ECMAScript 的演算法非常複雜,為了避免文章過於龐大,會將其拆成 2 天介紹:
第 1 天 (Day 26):
第 2 天 (Day 27)
splice()
這個 method 的全寫應該是 Array.prototype.splice
,有興趣可以看 Day 2 的介紹,這邊會直接使用 splice()
作為替代。
範例的 callback 都會使用箭頭函式做介紹,如果尚不熟悉的話可以參考 MDN 的介紹。
最後會透過分析 ECMAScript 來驗證是否有吻合,如果覺得 ECMAScript 有點艱澀難懂,我們在 Day 4 、Day 5 有介紹其相關術語可以幫助閱讀。
當你想要直接修改陣列中的元素時。
splice()
會根據 3 個參數 - 起始點、欲刪除元素數量、欲添加元素,來決定如何修改原陣列。
splice(start)
splice(start, deleteCount)
splice(start, deleteCount, ...itemN)
splice()
可接受 3 個以上的參數,前 2 個分別是 start
及 deleteCount
,之後便是 0 至多個 ...itemN
。
在以下的描述中,陣列長度都會使用 length
來表示。
start
splice()
用來修改陣列的起始點,也就是準備刪除元素的起始點,也是欲添加元素的起始點。
start
的值可以是一個正負數,會有以下狀況:
length
則視為 length
,也就表示不會有元素被刪除,且新元素會從陣列最末端開始添加。length + start
,因此 -1
會等於陣列的最後一個元素,以此類推...。如果相加後仍小於 0 則視為 0。1.2
-> 1
、 -1.2
-> -1
deleteCount
欲刪除的元素數量,會從 start
開始刪除指定數量的元素。
如果不提供、或其值 ≥ length - start
(表示刪除的數量大於等於從 start
開始計算的數量),因此從 start
開始之後 (包括 start
) 的元素將被全部刪除。
如果其值為 0 或 負數,則不會有任何元素被移除。
...itemN
欲添加的新元素,會從 start
開始添加新的元素。
如果沒有提供,則 splice()
只會從陣列中移除元素,不會添加元素。
splice()
會在修改原陣列後回傳被刪除的元素陣列。
如果沒有元素被刪除,則回傳空陣列。
會改動到原陣列。
splice()
會跟據給予的參數修改原陣列,也就是說它會改變 this
所指向的物件,一般來說會是呼叫它的陣列。
如果新增加的元素數量跟刪除的元素數量不一樣時,陣列的 length
會被改變,這點是必要的,因為如果 splice()
沒有隨之改變 length
將會產生非預期的 empty slot,詳細可以參考 Day 27 的介紹。
splice()
會使用到 @@species
這個 well-known Symbol 來創造一個新陣列,並將其回傳,詳細可參考 Day 27 的介紹。
splice()
如果移除了稀疏陣列的 empty slot,那回傳的新陣列也會包含被移除的 empty slot。
const names = ['Cate', 'Emma', 'Alejo', 'Russ']
console.log(names.splice(1, 1))
// ['Emma']
console.log(names)
// ['Cate', 'Alejo', 'Russ']
console.log(names.splice(1, 0, 'Emma'))
// []
console.log(names)
// ['Cate', 'Emma', 'Alejo', 'Russ']
console.log(names.splice(1, 1, 'Pedro'))
// ['Emma']
console.log(names)
// ['Cate', 'Pedro', 'Alejo', 'Russ']
console.log(names.splice(4, 0, 'Anita'))
// []
console.log(names)
// ['Cate', 'Pedro', 'Alejo', 'Russ', 'Anita']
注意原陣列一直不斷地被改動!
start
使用負數、小數或超出範圍const names = ['Cate', 'Emma', 'Alejo', 'Russ']
console.log([...names].splice(1.1, 1))
// ['Emaa']
console.log([...names].splice(2.7, 1))
// ['Ajejo']
console.log([...names].splice(-1, 1))
// ['Russ']
console.log([...names].splice(-1.9, 1))
// ['Russ']
console.log([...names].splice(4, 2, 'newOne'))
// []
console.log([...names].splice(-7, 1))
// ['cate']
這邊使用展開運算子 (spread operator, ...
) 先複製原陣列再進行操作,以免改動到原陣列。
const names = ['Cate', 'Emma', 'Alejo', 'Russ']
// 1. with map()
console.log(names.map(item => item).splice(1, 1))
// ['Emma']
console.log(names)
// ['Cate', 'Emma', 'Alejo', 'Russ']
// 2. with spread syntax
console.log([...names].splice(1, 1))
// ['Emma']
console.log(names)
// ['Cate', 'Emma', 'Alejo', 'Russ']
// 3. with filter()
console.log(names.filter(() => true).splice(1, 1))
// ['Emma']
console.log(names)
// ['Cate', 'Emma', 'Alejo', 'Russ']
// 4. with slice()
console.log(names.slice().splice(1, 1))
// ['Emma']
console.log(names)
// ['Cate', 'Emma', 'Alejo', 'Russ']
// 5. with concat()
console.log(names.concat().splice(1, 1))
// ['Emma']
console.log(names)
// ['Cate', 'Emma', 'Alejo', 'Russ']
// 6. with reduce()
console.log(names.reduce((duplicate, name) => {
duplicate.push(name)
return duplicate
}, []).splice(1, 1))
// ['Emma']
console.log(names)
// ['Cate', 'Emma', 'Alejo', 'Russ']
// 7. with Array.from()
console.log(Array.from(names).splice(1, 1))
// ['Emma']
console.log(names)
// ['Cate', 'Emma', 'Alejo', 'Russ']
為了保持 immutable 的原則,我們應該儘量不改動原陣列!這邊使用了 7 種方法來淺拷貝 (shallow copy) 原陣列。
const fakeArray = {
0: 0,
1: 1,
2: 2,
notMyBussiness: 'Hi!',
length: 4
}
console.log([].splice.call(fakeArray, 1, 1, 'newOne'))
// [1]
console.log(fakeArray)
// {0: 0, 1: 'newOne', 2: 2, notMyBussiness: 'Hi!', length: 4}
splice()
被刻意做成通用的咩色,因此有著 length
屬性的類陣列物件也可以使用。
reverse()
被刻意做成通用的,擁有 length
屬性的類陣列物件都可以使用這個咩色;但要注意的是, 字串雖然也是類陣列的一種,但由於它是不可改變的(Immutable ),因此並沒有辦法適用這個咩色,我們來驗證一下:
start
跟 deleteCount
都可以使用小數,splice()
會自動將其轉換成整數,但有可能會跟預期的不一樣,詳細可參考 Day 27 的介紹。
由於 splice()
會直接改動原陣列,如果想要遵守 immutable 的原則,可以先對原陣列做淺拷貝 (shallow) 再使用 splice()
;如果組合其他咩色可以達到相同的目的 (例如 slice
),那可以考慮不使用這類會直接變動原陣列的咩色,可以參考範例的 Example 2。
由於 splice()
的篇幅較為龐大,所以這邊將 ECMAScript 的部分獨立出來,我們會於明天 (Day 27) 做介紹,虱目魚 die 吧!
最後,希望大家可以開心地使用各種咩色,體驗它帶給你的便利,祝大家歸剛沒煩惱。