Array.prototype.filter()

filter() 方法创建给定数组一部分的浅拷贝,其包含通过所提供函数实现的测试的所有元素。

尝试一下

语法

js
filter(callbackFn)
filter(callbackFn, thisArg)

参数

callbackFn

为数组中的每个元素执行的函数。它应该返回一个真值以将元素保留在结果数组中,否则返回一个假值。该函数被调用时将传入以下参数:

element

数组中当前正在处理的元素。

index

正在处理的元素在数组中的索引。

array

调用了 filter() 的数组本身。

thisArg可选

执行 callbackFn 时用作 this 的值。参见迭代方法

返回值

返回给定数组的一部分的浅拷贝,其中只包括通过提供的函数实现的测试的元素。如果没有元素通过测试,则返回一个空数组。

描述

filter() 方法是一个迭代方法。它为数组中的每个元素调用提供的 callbackFn 函数一次,并构造一个由所有返回真值的元素值组成的新数组。未通过 callbackFn 测试的数组元素不会包含在新数组中。

callbackFn 仅对已分配值的数组索引调用。它不会对稀疏数组中的空槽调用。

filter() 方法是一个复制方法。它不会改变 this,而是返回一个包含与原始数组相同的元素(其中某些元素已被过滤掉)的浅拷贝。但是,作为 callbackFn 的函数可以更改数组。请注意,在第一次调用 callbackFn 之前,数组的长度已经被保存。因此:

  • 当开始调用 filter() 时,callbackFn 将不会访问超出数组初始长度的任何元素。
  • 对已访问索引的更改不会导致再次在这些元素上调用 callbackFn
  • 如果数组中一个现有的、尚未访问的元素被 callbackFn 更改,则它传递给 callbackFn 的值将是该元素被修改后的值。被删除的元素则不会被访问。

警告: 上述类型的并发修改经常导致难以理解的代码,通常应避免(特殊情况除外)。

filter() 方法是通用的。它只期望 this 值具有 length 属性和整数键属性。

示例

筛选排除所有较小的值

以下示例使用 filter() 创建一个过滤数组,该数组删除了所有值小于 10 的元素。

js
function isBigEnough(value) {
  return value >= 10;
}

const filtered = [12, 5, 8, 130, 44].filter(isBigEnough);
// filtered is [12, 130, 44]

找出数组中所有的素数

下面的例子返回数组中的所有素数:

js
const array = [-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];

function isPrime(num) {
  for (let i = 2; num > i; i++) {
    if (num % i === 0) {
      return false;
    }
  }
  return num > 1;
}

console.log(array.filter(isPrime)); // [2, 3, 5, 7, 11, 13]

过滤 JSON 中的无效条目

以下示例使用 filter() 创建具有非零 id 的元素的 json。

js
const arr = [
  { id: 15 },
  { id: -1 },
  { id: 0 },
  { id: 3 },
  { id: 12.2 },
  {},
  { id: null },
  { id: NaN },
  { id: "undefined" },
];

let invalidEntries = 0;

function filterByID(item) {
  if (Number.isFinite(item.id) && item.id !== 0) {
    return true;
  }
  invalidEntries++;
  return false;
}

const arrByID = arr.filter(filterByID);

console.log("过滤后的数组\n", arrByID);
// 过滤后的数组
// [{ id: 15 }, { id: -1 }, { id: 3 }, { id: 12.2 }]

console.log("无效条目数量 =", invalidEntries);
// 无效条目数量 = 5

在数组中搜索

下例使用 filter() 根据搜索条件来过滤数组内容。

js
const fruits = ["apple", "banana", "grapes", "mango", "orange"];

/**
 * 根据搜索条件(查询)筛选数组项
 */
function filterItems(arr, query) {
  return arr.filter((el) => el.toLowerCase().includes(query.toLowerCase()));
}

console.log(filterItems(fruits, "ap")); // ['apple', 'grapes']
console.log(filterItems(fruits, "an")); // ['banana', 'mango', 'orange']

在稀疏数组上使用 filter()

filter() 将跳过空槽。

js
console.log([1, , undefined].filter((x) => x === undefined)); // [undefined]
console.log([1, , undefined].filter((x) => x !== 2)); // [1, undefined]

在非数组对象上调用 filter()

filter() 方法读取 thislength 属性,然后访问每个整数索引。

js
const arrayLike = {
  length: 3,
  0: "a",
  1: "b",
  2: "c",
};
console.log(Array.prototype.filter.call(arrayLike, (x) => x <= "b"));
// [ 'a', 'b' ]

影响初始数组(修改、追加和删除)

下面的示例测试在修改数组时 filter() 方法的行为。

js
// 修改每个单词
let words = ["spray", "limit", "exuberant", "destruction", "elite", "present"];

const modifiedWords = words.filter((word, index, arr) => {
  arr[index + 1] += " extra";
  return word.length < 6;
});

console.log(modifiedWords);
// 注意,在长度为 6 以下有三个单词,但是由于它们已经被修改,所以返回一个单词
// ["spray"]

// 添加新单词
words = ["spray", "limit", "exuberant", "destruction", "elite", "present"];
const appendedWords = words.filter((word, index, arr) => {
  arr.push("new");
  return word.length < 6;
});

console.log(appendedWords);
// 只有三个符合条件,即使 `words` 本身现在有更多字符长度小于 6 的单词
// ["spray" ,"limit" ,"elite"]

// 删除单词
words = ["spray", "limit", "exuberant", "destruction", "elite", "present"];
const deleteWords = words.filter((word, index, arr) => {
  arr.pop();
  return word.length < 6;
});

console.log(deleteWords);
// 注意我们没有得到 'elite',因为它在过滤器访问到它之前就已经从 'words' 弹出了
// ["spray" ,"limit"]

规范

Specification
ECMAScript Language Specification
# sec-array.prototype.filter

浏览器兼容性

BCD tables only load in the browser

参见