11-数组搜索
8.3 数组搜索
如果想在数组中查找元素,有以下几种选择。从最简单的 indexOf 开始介绍,JavaScript很久以前就开始支持它了。 indexOf 将返回跟所要查找的内容完全相同的第一个元素的下标(对应的还有 lastIndexOf() ,从数组末尾开始查找,同样返回完全匹配的第一个元素的下标)。如果只想在数组的某一部分查找,可以指定查找的起始下标。如果 indexOf (或者 lastIndexOf() )返回−1,则表示没有匹配的元素:
const o = { name: "Jerry" };
const arr = [1, 5, "a", o, true, 5, [1, 2], "9"];
arr.indexOf(5); // returns 1
arr.lastIndexOf(5); // returns 5
arr.indexOf("a"); // returns 2
arr.lastIndexOf("a"); // returns 2
arr.indexOf({ name: "Jerry" }); // returns -1
arr.indexOf(o); // returns 3
arr.indexOf([1, 2]); // returns -1
arr.indexOf("9"); // returns 7
arr.indexOf(9); // returns -1
arr.indexOf("a", 5); // returns -1
arr.indexOf(5, 5); // returns 5
arr.lastIndexOf(5, 4); // returns 1
arr.lastIndexOf(true, 3); // returns -1
另一个查找元素的方法是 findIndex ,它与 indexOf 一样,返回一个下标(返回−1表示没有匹配元素)。相比于 indexOf , findIndex 更灵活,因为它可以指定一个函数来表示元素是否匹配( findIndex 不能指定查找的起始位置,不过它有对应的 findLastIndex 函数):
const arr = [{ id: 5, name: "Judith" }, { id: 7, name: "Francis" }];
arr.findIndex(o => o.id === 5); // returns 0
arr.findIndex(o => o.name === "Francis"); // returns 1
arr.findIndex(o => o === 3); // returns -1
arr.findIndex(o => o.id === 17); // returns -1
find 还是一个用于查找的方法,它和 findIndex 都很适合查找特定元素的下标。不过,如果并不关心元素下标,只想返回元素本身呢?像 findIndex 一样, find 也允许指定一个函数来进行查找,只不过它会返回元素本身而非元素下标(没找到元素时返回 null )。
const arr = [{ id: 5, name: "Judith" }, { id: 7, name: "Francis" }];
arr.find(o => o.id === 5); // returns object { id: 5, name: "Judith" }
arr.find(o => o.id === 2); // returns null
那些传入 find 和 findIndex 中的函数,会把数组的每一个元素作为第一个参数,其他参数还有当前元素的下标和数组本身。它们可以完成这样一些事情,比如:寻找以指定下标开始的元素的平方数。
const arr = [1, 17, 16, 5, 4, 16, 10, 3, 49];
arr.find((x, i) => i > 2 && Number.isInteger(Math.sqrt(x)));// returns 4
find 和 findIndex 还允许在方法调用过程中指定 this 变量使用的值。它们可以用在需要调用某个对象方法的场景中。以下这些方法都会在 Person 对象中通过ID来查找元素,对比一下这些实现:
class Person {
constructor(name) {
this.name = name;
this.id = Person.nextId++;
}
}
Person.nextId = 0;
const jamie = new Person("Jamie"),
juliet = new Person("Juliet"),
peter = new Person("Peter"),
jay = new Person("Jay");
const arr = [jamie, juliet, peter, jay];
// 选项 1: 直接比较ID:
arr.find(p => p.id === juliet.id); // 返回juliet 对象
// 选项2: 使用 "this"参数:
arr.find(function(p)(return p.id === this.id, juliet); // 返回 juliet 对象
大家可能会发现在 find 和 findIndex 中, this 值的作用是有限的。但实际上这是后面会讲到的技术,届时它将会变得更加实用。
正如并不总关心数组中元素的索引一样,有时候甚至不关心下标或是元素本身,只想单纯的知道这个元素是否存在。显然,可以使用之前提到的函数来检查元素是否存在,看它是返回−1还是 null ,不过,JavaScript专门提供了两个方法来解决这个问题: some 和 every 。
一旦找到符合条件的元素(只需要一个符合条件的元素,所以在找到第一个元素后会停止查找), some 方法就会返回 true ,否则返回 false 。例如:
const arr = [5, 7, 12, 15, 17];
arr.some(x => x%2===0); // true; 12 是偶数
arr.some(x => Number.isInteger(Math.sqrt(x))); // false; 没有平方数
而当数组中的每个元素都符合条件的时候, every 方法才会返回 true ,否则返回 false 。当 every 方法发现一个不符合条件的元素时,就会停止查找并返回 false ;否则,会扫描整个数组:
const arr = [4, 6, 16, 36];
arr.every(x => x%2===0); // true; 没有奇数
arr.every(x => Number.isInteger(Math.sqrt(x))); // false; 6不是平方数
像本章中所提及的其他方法一样, some 和 every 也可以接收一个方法作为参数,它们还能再接收一个参数,用来指定方法被调用时的 this 值。