[JS] Array
備註
Change Log
- 2023:Initial version
- 2026/01/06:Fix code examples and refine explanations
新增元素
push:往陣列後加元素
const numbers = [1, 2, 3, 4, 5, 6, 7, 8]
numbers.push(9, 10)
console.log(numbers) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
unshift:往陣列前方加元素
const numbers = [1, 2, 3, 4, 5, 6, 7, 8]
numbers.unshift(-1, 0)
console.log(numbers) // [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8]
[]:直接指定元素添加或更改位置
const numbers = [1, 2, 3, 4, 5, 6, 7, 8]
numbers[5] = 'six'
console.log(numbers) // [1, 2, 3, 4, 5, 'six', 7, 8]
刪除
pop:刪除陣列後方一個元素並回傳刪掉的值
const numbers = [1, 2, 3, 4, 5, 6, 7, 8]
const removeNum = numbers.pop()
console.log(removeNum) // 8
console.log(numbers) // [1, 2, 3, 4, 5, 6, 7]
shift:刪除陣列前方一個元素並回傳刪掉的值
const numbers = [1, 2, 3, 4, 5, 6, 7, 8]
const removeNum = numbers.shift()
console.log(removeNum) // 1
console.log(numbers) // [2, 3, 4, 5, 6, 7, 8]
delete:刪除陣列指定位置元素,但不影響陣列長度
const numbers = [1, 2, 3, 4, 5, 6, 7, 8]
delete numbers[5]
console.log(numbers) // [1, 2, 3, 4, 5, <empty>, 7, 8]
注意
delete 會留下空洞(hole),通常不建議用於陣列,實務上多半使用 splice 或產生新陣列。
但 delete 如果放在 object 的應用上就有是不錯的選擇。
裁切
splice(start, delete, insert):對原陣列直接做裁切並傳回裁切的部分。接受三個參數,第一個是要刪除或插入的「索引位置」;第二個是「刪除的元素數」,0 是不刪除只插入,不填是刪除索引位置後面所有的元素;第三個是要「插入的值」。
const numbers = [1, 2, 3, 4, 5, 6, 7, 8]
const spliceValue = numbers.splice(5, 2, 'six', 'seven')
console.log(spliceValue) //[6, 7]
console.log(numbers) // [1, 2, 3, 4, 5, 'six', 'seven', 8]
slice(start, end):不修改原陣列,而是會回傳新陣列 (原陣列中的一部分)。接受兩個參數,第一個是「開始的位置」;第二個是「結束的位置」,不代入參數就會提取到最後一筆資料,代入負數表示提取到倒數第幾個資料;都不帶參數會複製一個完整陣列。
const numbers = [1, 2, 3, 4, 5, 6, 7, 8]
const newNumbers = numbers.slice(2, 5)
console.log(newNumbers) // [3, 4, 5]
copyWithin(index, start, end):會修改原陣列的操作方式。語法內容是把start到end位置中的內容複製下來,然後從index的位置貼上覆蓋原本的內容。
const numbers = [1, 2, 3, 4, 5, 6, 7, 8]
numbers.copyWithin(1, 5, 8)
console.log(numbers) // [1, 6, 7, 8, 5, 6, 7, 8]
排序
sort:會操作原陣列。參數可以接受自己寫的函式,也建議自己簡短寫一個函式,因為不帶參數的sort表現有點一言難盡...。
// 先創個混亂排序陣列
const newNumbers = [10, 5, 8, 2, 4, 1, 0]
// 單純用 sort() 不帶參數
newNumbers.sort()
console.log(newNumbers) //[0, 1, 10, 2, 4, 5, 8]
// 寫個函式代入參數
const Sorting = (a, b)=>{
if(a > b){
return 1
}else if(a < b){
return -1
}else{
return 0
}
}
newNumbers.sort(Sorting)
console.log(newNumbers) //[0, 1, 2, 4, 5, 8, 10]
reverse:將陣列倒轉
const numbers = [1, 2, 3, 4, 5, 6, 7, 8]
numbers.reverse()
console.log(numbers) // [8, 7, 6, 5, 4, 3, 2, 1]
篩選與搜尋
filter,會回傳一個符合條件的新陣列。接受一個 callback 函式做為參數,該函式又接受三個參數:item,index,array。item:正在被處理的元素index:當前元素的索引位置array:正在遍歷的陣列
const numbers = [1, 2, 3, 4, 5, 6, 7, 8]
const filterNum = numbers.filter((item)=>{
return item > 5
})
console.log(filterNum) // [6, 7, 8]
提示
const numInBoolean = [0, 0, 1, 0, 1, 1, 0, 1]
const filterNum = numInBoolean.filter(Boolean)
console.log(filterNum) // [1, 1, 1, 1]
猜猜上面反還的為何是 [1, 1, 1, 1]?
因為 Boolean 會將 0 轉為 false,1 轉為 true,所以 filter 會回傳 true 的值。
filter(Boolean) 通常拿來排除陣列中的 false、null、0、""、undefined、NaN,屬於 filter 的一個小技巧~
find:跟filter類似,但返回的是符合後方條件的第一個值。現在代入跟上面filter一樣的條件
const numbers = [1, 2, 3, 4, 5, 6, 7, 8]
const findNum = numbers.find((item)=>{
return item > 5
})
console.log(findNum) // 6
indexOf:查詢某元素的陣列索引位置。帶兩個參數,第一個是「查尋的元素」,第二個是要「開始查詢的位置」。
const numbers = [1, 2, 3, 4, 5, 6, 7, 8]
const index = numbers.indexOf(6)
console.log(index) // 5
includes:查詢陣列中是否帶有某元素。所帶參數跟indexOf一樣
const numbers = [1, 2, 3, 4, 5, 6, 7, 8]
console.log(numbers.includes(6)) // true
迭代
forEach:可以看做是陣列的迴圈,不會修改原陣列也不會回傳任何值,就僅僅是依開發者想要對陣列中的元素做什麼操作
const numbers = [1, 2, 3, 4, 5, 6, 7, 8]
const doubleNumbers = []
numbers.forEach((number)=>{
const newNum = number * 2
doubleNumbers.push(newNum)
})
console.log(doubleNumbers) // [2, 4, 6, 8, 10, 12, 14, 16]
map:跟forEach不一樣,它會回傳一個新陣列。上述的內容改成map會變這樣
const numbers = [1, 2, 3, 4, 5, 6, 7, 8]
const doubleNumbers = numbers.map((number)=>{
return number * 2
})
console.log(doubleNumbers) // [2, 4, 6, 8, 10, 12, 14, 16]
reduce:陣列計算。它接受兩個參數,一個是 callback function,一個是預設值。- callback function 可以帶的參數:
accumulator:目前計算後的值。currentValue:正在處理的元素。currentIndex:當前元素的索引位置。array:當前操作的陣列。
- initialValue:預設值,不提供會默認第一個元素的值為預設值。
- callback function 可以帶的參數:
const numbers = [1, 2, 3, 4, 5, 6, 7, 8]
const sum = numbers.reduce((x, y)=>{
return x + y
})
console.log(sum) // 36
every:用來檢查陣列中的元素是否都滿足特定條件,如果只想要部分滿足可以改成some。
const numbers = [1, 2, 3, 4, 5, 6, 7, 8]
console.log(numbers.every(number => number > 6)) // false,不是每個數字都大於6
console.log(numbers.some(number => number > 6)) // true,有一些數字大於6
刪除重複
先來建立一個有重複數字的陣列。
const numbers = [1, 2, 3, 4, 4, 4, 5, 6, 7, 8, 8, 8]
filter:
const newNumbers = numbers.filter((item, index)=>{
return numbers.indexOf(item) === index
})
console.log(newNumbers) // [1, 2, 3, 4, 5, 6, 7, 8]
set:快速解決重複的方法,對原陣列直接執行操作不產生新陣列
const numbers = [1, 2, 3, 4, 4, 4, 5, 6, 7, 8, 8, 8]
const uniqueNumbers = [...new Set(numbers)]
console.log(uniqueNumbers) // [1, 2, 3, 4, 5, 6, 7, 8]
資訊
推薦使用 set 來刪除重複
合併
concat:用來合併陣列,會回傳新陣列
const numbers = [1, 2, 3, 4, 5, 6, 7, 8]
const secondNumbers = [9, 10, 11]
const newNumbers = numbers.concat(secondNumbers)
console.log(newNumbers) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
陣列轉字串
join:裡面帶分隔符,不指定會以逗號隔開
const numbers = [1, 2, 3, 4, 5, 6, 7, 8]
const string1 = numbers.join()
console.log(string1) // 1,2,3,4,5,6,7,8
const string2 = numbers.join('')
console.log(string2) // 12345678
const string3 = numbers.join(' ') // 帶空格
console.log(string3) // 1 2 3 4 5 6 7 8
實務上遇到前輩使用的方法
Array.from
Array.from 是我在做 code review 時從一位前端前輩那裡學到的 array 操控方法,查了一下發現這方法真是好用。
他可以接受三個參數:
arrayLike:必填,可以是任何類型的資料,但必須是可迭代的。mapFn:選填,可以對每個元素做處理。接受兩個參數,第一個是當前元素的值,第二個是當前元素的索引位置。thisArg:選填,可以指定 mapFn 中的 this。
所以 Array.from 可以做什麼事?稍微列了一些例子:
- 陣列複製
const numbers = [1, 2, 3, 4, 5, 6, 7, 8]
const copy = Array.from(numbers)
console.log(copy) // [1, 2, 3, 4, 5, 6, 7, 8]
- 創建指定長度的陣列
const length = 5
const newArray = Array.from({length}, (v, i) => i)
console.log(newArray) // [0, 1, 2, 3, 4]
- 對陣列做處理
const numbers = [1, 2, 3, 4, 5, 6, 7, 8]
const doubleNumbers = Array.from(numbers, (number) => number * 2)
console.log(doubleNumbers) // [2, 4, 6, 8, 10, 12, 14, 16]
- 可迭代資料轉陣列
const string = 'hello'
const stringArray = Array.from(string)
console.log(stringArray) // ['h', 'e', 'l', 'l', 'o']
Summary
會修改原陣列的方法
一般這類方法因為直接對原資料出手,所以使用上需謹慎。
實務做法一般配合先複製一份原陣列來使用,避免直接改到原資料。
| 方法 | 說明 |
|---|---|
| push | 從尾端新增元素 |
| pop | 從尾端刪除一個元素 |
| unshift | 從前端新增元素 |
| shift | 從前端刪除一個元素 |
| splice | 插入、刪除或取代元素 |
| sort | 排序陣列 |
| reverse | 反轉陣列 |
| copyWithin | 複製指定區段並覆蓋原內容 |
| fill | 以固定值填滿指定區段 |
| delete | 刪除元素(留下 hole,不建議用於陣列) |
不會修改原陣列的方法
這類方法通常是回傳一個新陣列,或是回傳特定值,使用上相對安全很多。
因此一般資料操作多半會使用這類方法。
| 方法 | 說明 |
|---|---|
| map | 轉換每個元素並回傳新陣列 |
| filter | 篩選元素並回傳新陣列 |
| slice | 回傳陣列的子集合 |
| concat | 合併陣列並回傳新陣列 |
| flat | 攤平巢狀陣列並回傳新陣列 |
| flatMap | map + flat(回傳新陣列) |
| reduce | 將陣列聚合成單一值 |
| find | 回傳第一個符合條件的元素 |
| findIndex | 回傳第一個符合條件的索引 |
| indexOf | 查詢元素索引 |
| includes | 檢查是否包含指定元素 |
| join | 將陣列轉成字串 |
| toString | 將陣列轉成字串 |
| every | 檢查是否全部符合條件 |
| some | 檢查是否有部分符合條件 |
| entries | 回傳 iterator(不修改原陣列) |
| keys | 回傳索引 iterator |
| values | 回傳值 iterator |
| Array.from | 建立新陣列 |
Reference
- 實用 Array 陣列操作大全
- JS Array 刪除重複元素的三種方式
- JavaScript 大全 (第七版) / David Flanagan / 歐萊禮出版
- Javascript 的 Boolean 居然能這樣用(搭配 Array)