HOWTO · JavaScript

如何在 JavaScript 中依多個條件篩選陣列

本文將介紹如何在 JavaScript 中使用多個條件篩選陣列,並比較動態條件與固定條件的寫法。

本頁內容

使用 JavaScript 的 filter() 方法搭配判斷式,只在陣列元素符合所有必要條件時回傳 true。如果條件是在執行時才提供,逐一比對指定的屬性和值;如果條件已知,則用 && 串接各項比較。這兩種寫法都會讓 filter() 回傳只包含符合條件元素的新陣列。

在 JavaScript 中過濾多個條件

filter() 會針對陣列中每個已設定的元素呼叫回呼函式,並在回呼結果為真值時保留該元素。它不會把元素改成 true 或 false,也不會改動原始陣列。回呼函式會收到目前元素、索引及原陣列;大多數判斷式只需要使用元素。回傳的是新陣列,但其中符合條件的物件仍與來源陣列中的物件參照相同。

filter(callbackFn)

callbackFn 是判斷式,用來檢查元素並回傳真值或假值。如果沒有任何元素符合條件,回傳的陣列會是空陣列。稀疏陣列中未設定值的空槽會被略過,因為回呼函式不會收到這些索引。如需完整的回呼函式簽章與行為,請參閱 MDN 的 filter() 文件。

使用傳統方法

當條件集合來自表單或其他資料來源時,可以將條件存入物件,再逐一檢查其中的項目。以下範例要求每個指定的鍵都是使用者物件本身的屬性,而且屬性值必須完全相同。給定的條件會選出 Aleena,因為她的姓名與地址都符合。

const criteria = {
  address: 'India',
  name: 'Aleena'
};
const users = [
  {name: 'John Doe', email: 'johndoe@mail.com', age: 25, address: 'USA'},
  {name: 'Aleena', email: 'aleena@mail.com', age: 35, address: 'India'},
  {name: 'Mark Smith', email: 'marksmith@mail.com', age: 28, address: 'England'}
];

const filteredUsers = users.filter((user) => {
  return Object.entries(criteria).every(([key, value]) =>
    Object.prototype.hasOwnProperty.call(user, key) && user[key] === value
  );
});

console.log(filteredUsers);
[
  {
    name: 'Aleena',
    email: 'aleena@mail.com',
    age: 35,
    address: 'India'
  }
]

Object.entries(criteria) 會提供各組屬性與值,而 every() 會要求每一組都符合。嚴格相等運算子(===)會同時比對值與型別;如果物件缺少指定屬性,就不會符合該條件。若條件物件是空的,every() 對每位使用者都會回傳 true,因此結果會包含所有使用者。這種寫法可配合任意一組鍵,不必為每個欄位另外撰寫比較式。

檢查屬性是否為物件本身所有,也能避免繼承而來的屬性被誤認為符合指定鍵。若資料位於巢狀物件中,請明確比對巢狀值,或為該欄位提供判斷式;本例直接比對的是最上層屬性值。

使用 filter() 方法

如果條件固定且事先已知,可以直接在判斷式中寫出各項條件,並以邏輯 AND 運算子(&&)連接。只有每項比較都成立時,使用者才會被保留。這個完整範例使用相同的資料,篩選結果也與動態條件的版本相同。

const filter = {
  address: 'India',
  name: 'Aleena'
};
const users = [
  {name: 'John Doe', email: 'johndoe@mail.com', age: 25, address: 'USA'},
  {name: 'Aleena', email: 'aleena@mail.com', age: 35, address: 'India'},
  {name: 'Mark Smith', email: 'marksmith@mail.com', age: 28, address: 'England'}
];

const filteredUsers = users.filter(
  (user) => user.name === filter.name && user.address === filter.address
);

console.log(filteredUsers);
[
  {
    name: 'Aleena',
    email: 'aleena@mail.com',
    age: 35,
    address: 'India'
  }
]

當欄位與比較規則屬於程式本身的邏輯時,適合使用這種直接寫法;當要求比對的欄位可能改變時,則適合使用動態寫法。也可以參閱原始的 JSFiddle 範例。

請讓判斷式專注於納入結果的規則:要保留的元素回傳真值,要排除的元素回傳假值。由於 && 會採用短路求值,只有前面的比較成立時才會執行後續比較。若某項較早的比較能以較低成本排除許多元素,可以調整檢查順序,同時確保條件的意思清楚。