實用陣列操作大全-進階使用方法


陣列裡是有順序的集合,每個元素因為有索引。所以可以用迴圈的方法來遍歷陣列裡的元素,來進行有條件的篩選。

最常用的就是 for 迴圈處理陣列元素的遍歷問題。

它的撰寫規則如下:

for ([initialization]; [condition]; [final-expression])
   statement
  • initialization:初始表達式,也就是按下計數器,從條件的初始值開始計算。
  • condition:判斷條件成不成立,如果回傳 true ,則迴圈繼續執行;如果為 false 則迴圈終止。
  • final-expression:遞增表達式,每次迴圈執行完,判斷條件加 1 ,直到判斷條件不成立。

假設我們要依序印出 avangers 這個超級英雄的陣列元素,用 for 迴圈可以這樣做:

const avengers = ['鋼鐵人', '美國隊長', '浩克', '雷神', '驚奇隊長'];
for (let i = 0; i < avengers.length; i++){
    console.log(i + avengers[i]);
}
// 依序印出:
// 0鋼鐵人
// 1美國隊長
// 2浩克
// 3雷神
// 4驚奇隊長

可以看出 for 迴圈是依照條件,不斷地透過索引去撈出陣列中對應的元素(遍歷整個陣列),然後一次一次印出迴圈中的元素。直到條件不符合,才終止迴圈的執行。

但是現在操作陣列不用那麼麻煩,ES5之後,新增了許多操作陣列的方法,讓我們一起來看看吧!

Array.prototype.forEach()

forEach() 方法會將陣列內的每個元素,皆傳入並執行給定的函式一次。
直接修改原本的陣列。

arr.forEach(function (currentValue[, index[, array]]) {
    //your iterator
});
  • function : 給定的函式,是一個 callBack function,會把陣列中的每個元素當作參數帶入陣列中,每個元素執行一次。
  • currentValue : 這個參數代表陣列中輪到被函式處理的元素。
  • index : 這個參數代表陣列中正在被函式處理的元素的索引值。可省略。
  • array : 代表被執行的陣列。可省略。
const avengers = ['鋼鐵人', '美國隊長', '浩克', '雷神'];
let newArray = avengers.forEach(function(item,index,array){
    console.log(`${item} 的索引值是 ${index},陣列的內容是 [${array}]`)
})
// 鋼鐵人 的索引值是 0,陣列的內容是 [鋼鐵人,美國隊長,浩克,雷神]
// 美國隊長 的索引值是 1,陣列的內容是 [鋼鐵人,美國隊長,浩克,雷神]
// 浩克 的索引值是 2,陣列的內容是 [鋼鐵人,美國隊長,浩克,雷神]
// 雷神 的索引值是 3,陣列的內容是 [鋼鐵人,美國隊長,浩克,雷神]
console.log(newArray);
// undefined

和 for 迴圈比較起來, forEach 不用設定任何條件,也不用初始化,就可以把每個元素傳入函式中執行。

要注意的是 forEach 方法不會回傳任何的值,所以 console.log 的值是「 Uncaught ReferenceError: newArray is not defined 」。

另外,for 迴圈可以使用 break 跳出,但是 forEach()如果使用break會紅字報錯。

const avengers = ['鋼鐵人', '美國隊長', '浩克', '雷神'];
avengers.forEach(function(item){
    if (item ==='美國隊長' ){
      break;
    //Uncaught SyntaxError: Illegal break statement 
    }
})

forEach也不會理會使用return的方法中止程式執行,會一路跑完。

const avengers = ['鋼鐵人', '美國隊長', '浩克', '雷神'];
avengers.forEach(function(item){
    if (item ==='美國隊長' ){
      return;
    }
})
console.log(avengers)
//["鋼鐵人","美國隊長","浩克","雷神"]

array.prototype.map

map() 方法會建立一個新的陣列,其內容為原陣列的每一個元素經由回呼函式運算後所回傳的結果之集合。

也就是我們使用 map() 的時候,會透過給定的函式條件處理原來的陣列,再回傳一個新的陣列。

語法:

let new_array = arr.map(function callback( currentValue[, index[, array]]) {
    // return element for new_array
}[, thisArg])
  • function : 給定的函式是一個回呼函式。會把陣列中的每個元素當作參數帶入陣列中,每個元素執行一次。
  • index : 處理中的元素索引。
  • array : 當前函式處理的陣列。

範例:找出名字的字串長度是2的超級英雄。

const avengers = ['鋼鐵人', '美國隊長', '浩克', '雷神'];
let newArray = avengers.map(function(item){
    if(item.length === 2){
        return item;
    }
})
console.log(newArray)
//[undefined, undefined, '浩克', '雷神']

map() 的特色是:

  1. 適合用來篩選特定資料。
  2. map() 所帶函式回傳的值,會組成一個新的陣列回傳。
  3. 不會改變原來的陣列。
  4. 回傳的陣列長度會等於原始的陣列長度。
  5. 如果沒有回傳值,則元素的值為undefined。

上面的範例,如果寫法照搬,只把 map 改成 forEach:

const avengers = ['鋼鐵人', '美國隊長', '浩克', '雷神'];
let newArray = avengers.forEach(function(item){
    if(item.length === 2){
        return item;
    }
})
console.log(newArray)
//undefined
console.log(avengers)
["鋼鐵人","美國隊長","浩克","雷神"]

forEach 方法不會回傳值,所以 newArray 查詢的結果是 undefined。而 avengers 原始陣列也沒有被改變。

如果要改變原始陣列的話,要這樣子寫:

const avengers = ['鋼鐵人', '美國隊長', '浩克', '雷神'];
let newArray = avengers.forEach(function(item,index,array){
    if(item.length === 2){
        array[index] = item;
    }else{
      array[index] = "undefined";
    }
})
console.log(newArray)
//undefined
console.log(avengers)
//['undefined', 'undefined', '浩克', '雷神']

因為forEach不會回傳值, let newArray = 這一段其實不用寫了,寫出來只是為了方便比較。

Array.prototype.filter()

filter() 方法會建立一個經指定之函式運算後,由原陣列中通過該函式檢驗之元素所構成的新陣列。

語法如下:

var newArray = arr.filter(callback(element[, index[, array]])[, thisArg])
  • element : 當前處理到的元素。
  • index : 給定函式目前處理的元素索引。可省略。
  • array : 給定函式目前處理的陣列。可省略。

範例:

const avengers = ['鋼鐵人', '美國隊長', '浩克', '雷神'];
let newArray = avengers.filter(function(item){
    return item.length === 2 ;
    
})
console.log(newArray)
["浩克","雷神"]
console.log(avengers)
["鋼鐵人","美國隊長","浩克","雷神"]

可以觀察到 filter 過濾出字串長度為 2 的陣列元素,並回傳一個新的陣列。而原來的陣列沒被改變。

filter()也可以用來過濾掉陣列中的重複值:

const avengers = ['鋼鐵人', '美國隊長', '浩克','鋼鐵人', '雷神','美國隊長'];
let newArray = avengers.filter(function (item,index,array){
    console.log(avengers.indexOf(item));
    //回傳第一個找到的元素索引
    console.log(index);
    //函式當前處理的元素索引
    return avengers.indexOf(item) === index;
    //當第一個找到的元素索引等於函式目前處理的元素索引
})
console.log(newArray);
//["鋼鐵人","美國隊長","浩克","雷神"]
const avengers = [
    {
        name: '鋼鐵人',
        firePower: 10,
        bodyForce: 5
    },
    {
        name: '美國隊長',
        firePower: 5,
        bodyForce: 8
    },
    {
        name: '浩克',
        firePower: 0,
        bodyForce: 10
    }
]

const  newAvengers= avengers.filter(member => member.firePower >= 5);
console.log(newAvengers);

回傳值為一個新的陣列,陣列裡有 2 個物件, firePower 都大於或等於 5 :

Array.prototype.every()

every() 方法會測試陣列中的所有元素是否都通過了由給定之函式所實作的測試。
回傳值為布林值, true 或 false。

every() 方法可以用來檢測陣列中的元素是否符合特定條件。

語法:

var newArray = arr.every(callback(currentValue[, index[, array]])[, thisArg])
  • currentValue : 目前正被回呼函式處理的元素。
  • index : 目前被處理元素的陣列索引。可省略。
  • array : 目前被處理的陣列。可省略。
    const avengers = [
        {
            name: '鋼鐵人',
            firePower: 10,
            bodyForce: 5
        },
        {
            name: '美國隊長',
            firePower: 5,
            bodyForce: 8
        },
        {
            name: '浩克',
            firePower: 0,
            bodyForce: 10
        }
    ]
    const  isGoodPower= avengers.every(function(member) {
        return member.firePower >= 5;
    });
    console.log(isGoodPower);
    //false 並不是所有超級英雄的武裝火力都超過 5

Array.prototype.some()

some() 方法會透過給定函式、測試陣列中是否至少有一個元素,通過該函式所實作的測試。這方法回傳的是布林值。

也就是陣列中只要有一個元素符合指定函式的條件,就回傳 true ,否則就回傳 false 。

語法:

var newArray = arr.some(callback(currentValue[, index[, array]])[, thisArg])
  • currentValue : 目前正被回呼函式處理的元素。
  • index : 目前被處理元素的陣列索引。可省略。
  • array : 目前被處理的陣列。可省略。
const avengers = [
    {
        name: '鋼鐵人',
        firePower: 10,
        bodyForce: 5
    },
    {
        name: '美國隊長',
        firePower: 5,
        bodyForce: 8
    },
    {
        name: '浩克',
        firePower: 0,
        bodyForce: 10
    }
]
const  isGoodPower= avengers.some(function(member) {
    return member.firePower >= 5;
});
console.log(isGoodPower);
//true

Array.prototype.reduce()

MDN上寫著:

reduce() 方法將一個累加器及陣列中每項元素(由左至右)傳入回呼函式,將陣列化為單一值。

通常用來做陣列中數字的累加。

語法為:

arr.reduce(callback[accumulator, currentValue, currentIndex, array], initialValue)
  • accumulator:累加器,個別 currentValue 加總的累計值,如果是第一次呼叫,就看有沒有初始值來決定累加器一開始的值。
  • currentValue:陣列的個別元素
  • currentIndex:陣列的個別元素索引
  • array:回呼函式處理的陣列,可省略。
  • initialValue:預設值,可省略。
const avengers = [
    {
        name: '鋼鐵人',
        firePower: 10,
        bodyForce: 5
    },
    {
        name: '美國隊長',
        firePower: 5,
        bodyForce: 8
    },
    {
        name: '浩克',
        firePower: 0,
        bodyForce: 10
    }
]
let reduceAvenger = avengers.reduce(function(accumulator, currentValue){
    return accumulator + currentValue.firePower;
})
console.log(reduceAvenger);
//[object Object]50  !!!!
//因為未提供初始值,預設 陣列 第一個值,作為初始值。
//第一個值為一個 Object,結果造成非預期的錯誤

因為未提供初始值,所以出現了錯誤。

沒有預設值的話,accumulator(累計值)會取陣列的第一個元素當作預設值。所以我們加上預設值,再來一次。

const avengers = [
    {
        name: '鋼鐵人',
        firePower: 10,
        bodyForce: 5
    },
    {
        name: '美國隊長',
        firePower: 5,
        bodyForce: 8
    },
    {
        name: '浩克',
        firePower: 0,
        bodyForce: 10
    }
]
let reduceAvenger = avengers.reduce(function(accumulator, currentValue){
    return accumulator + currentValue.firePower;
},0)
console.log(reduceAvenger);
//15

reduce()也可以拿來合併陣列:

let avengers = [['鋼鐵人','蜘蛛人'],['浩克','雷神'],['美國隊長','黑寡婦']]
newAvengers = avengers.reduce((accumulator,currentValue)=>{
  return accumulator.concat(currentValue)
},[])
console.log(newAvengers)
//['鋼鐵人', '蜘蛛人', '浩克', '雷神', '美國隊長', '黑寡婦']

參考資料


實用陣列操作大全-進階使用方法
https://popeye-ux.github.io/2021/11/20/arrayAdvance/
作者
POPEYE
發布於
2021年11月20日
許可協議