HOWTO · JavaScript

在 JavaScript 中过滤多个条件

了解如何使用 JavaScript 的 filter() 方法,根据多个动态或固定条件筛选数组。

本页内容

使用 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() 方法

如果条件固定且预先已知,可以直接在谓词中写出这些条件,并用逻辑与运算符(&&)连接。只有每项比较都为真,该用户才会保留。下面是一个完整示例:它使用相同的数据,并筛选出与动态条件版本相同的用户。

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 示例。

谓词应只负责决定是否保留元素:要保留的元素应返回真值,要排除的元素应返回假值。由于 && 会短路求值,只有前面的比较通过后,后续比较才会执行。如果某个靠前的比较可以用很低的成本排除许多元素,可以调整检查顺序,同时确保条件含义清楚。