在前端开发中,经常会遇到判断数组中是否存在某个元素的情况。 我们来了解一下各个判断的方法。
在前端开发中,经常会遇到判断数组中是否存在某个元素的情况。 其实判断的方法有很多种,我们来一一了解。
我们先定义一个数组:
const arr = [
13,
false,
'abcd',
undefined,
13,
null,
NaN,
[1, 2],
{ a: 123 },
() => Date.now(),
new Date('2021/03/04'),
new RegExp('abc', 'ig'),
Symbol('sym'),
];
在这个数组中,我们包括了几种类型: 、 、 、 、 null、 array、 、 Date 等。数字 13 出现了 2 次。
这是我们最熟悉的一种。 毕竟它出现的早,兼容性好,使用起来也很方便。
如果该元素存在,则返回第一次出现的索引值; 如果整个数组中不存在该元素,则返回-1。
1.1 使用方法
只要判断返回的数据是否为-1,就可以知道该元素是否包含在数组中。
arr.indexOf(13) >= 0; // true, indexOf返回0
arr.indexOf(2) >= 0; // false, indexOf返回-1
相应地,从尾到前查找元素。 如果该元素存在,则返回数组中最后一个元素的索引; 如果该元素不存在,则返回-1。
arr.lastIndexOf(13) >= 0; // true, lastIndexOf返回4, 最后一次出现的索引
判断变量是否存在时,这两个方法的调用方式是一样的。
1.2 第二个可选参数
还有第二个可选参数,用于指示从哪个索引开始搜索。
中,如果超过数组长度,则直接返回-1,如果是负数,则从末尾算几个索引(arr.-Math.abs()),然后开始向后查找。
中,如果达到或超过数组长度,则搜索整个数组; 如果是负数,则从末尾算几个索引(arr.-Math.abs()),然后开始向前查找,如果负数的绝对值超过了数组的长度,则-1则直接返回。
arr.indexOf(13, 2); // 4, 从索引值2开始往后查找,首先找到的13的索引值为4
arr.indexOf(13, -10); // 4, 从索引值1(11-10)开始往后检索
arr.lastIndexOf(13, 2); // 0, 从索引值2往前开始搜索
arr.lastIndexOf(13, -2); // 4, 从索引值9(11-2)开始往前搜索
而且,和是按照严格相等的方式判断的(===)。
arr.indexOf(null); // 5, 在null的前面有几个假值false和undefined,也能准确找到null的索引值
主要目的是找到该元素所在的索引值,但是我们可以通过返回的索引值来间接判断该元素是否存在于数组中。
ES7()中添加的方法专门用于判断元素是否存在。 返回值true或false,true表示存在,false表示不存在,简单明了。
arr.includes(13); // true
arr.includes('abc'); // false
arr.includes(false); // true, 存在false元素
同时,该方法中还有第二个可选参数,其用法与 中相同。 如果超过数组长度,则直接返回-1,如果为负数,则从末尾开始数几个索引(arr.-Math.abs()),然后开始向后查找。
arr.includes(13, 5); // false, 从索引值5开始往后检索,没检索到
到目前为止,我们还没有对后面的类型进行判断,例如Array、Date和. 现在我们来判断接下来的几个要素:
// 使用indexOf判断
arr.indexOf(NaN); // -1
arr.indexOf([1, 2]); // -1
arr.indexOf({ a: 123 }); // -1
arr.indexOf(() => Date.now()); // -1
arr.indexOf(new Date('2021/03/04')); // -1
arr.indexOf(new RegExp('abc', 'ig')); // -1
arr.indexOf(Symbol('sym')); // -1
// 使用includes判断
arr.includes(NaN); // false
arr.includes([1, 2]); // false
arr.includes({ a: 123 }); // false
arr.includes(() => Date.now()); // false
arr.includes(new Date('2021/03/04')); // false
arr.includes(new RegExp('abc', 'ig')); // false
arr.includes(Symbol('sym')); // false
结局很悲惨,数组中没有检索到这些元素。 但事实上,它们都存在于数组中。
这是因为 和 是由严格相等(===)决定的。
NaN === NaN; // false, 两个NaN永远也不会相等
[1, 2] === [1, 2]; // false, 每个声明出来的数组都有单独的存储地址
{a: 123} === {a: 123}; // false, 同数组
new Date('2021/03/04')===new Date('2021/03/04'); // false, 看着日期是相同的,但是用new出来的对象进行比较的,肯定是不相等的
Symbol('sym')===Symbol('sym'); // Symbol类型的出现就是为了避免冲突创造出来的类型,括号里的属性仅是为了方便描述而已
对于这些无法检索到的类型,我们需要自己编写函数来判断特殊类型。
找到并
find() 和 () 允许我们通过回调函数自定义判断方式。
3.1 查找方法
find() 方法返回数组中满足所提供的测试函数的第一个元素的值。 否则返回。
find() 方法无法检测数组中的元素。
因为没有元素并且有元素,所以 find() 方法将返回。 这里我们就得考虑其他的方式,这个后面会讲到。
arr.find((item) => item === 13); // 13, 找到了元素13
arr.find((item) => item === 3); // undefined, 没找到元素3
arr.find((item) => item === undefined); // undefined, 也不知道是找到了还是没找到
对于上面稍微复杂的类型,我们需要特殊判断:
arr.find((item) => typeof item === 'number' && isNaN(item)); // NaN
// array和object类型进行比较时,情况很复杂,因为每个元素的类型都无法确定
// 如果确定都是基本类型,如string, number, boolean, undefined, null等,可以将其转为字符串再比较
// 转字符串的方式也很多,如JSON.stringify(arr), arr.toString(), arr.split('|')等
// 复杂点的,只能一项一项比较,或者使用递归
arr.find((item) => item.toString() === [1, 2].toString()); // [1, 2]
arr.find((item) => JSON.stringify(item) === JSON.stringify({ a: 123 })); // {a: 123}
arr.find((item) => {
if (typeof item === 'function') {
return item.toString() === (() => Date.now()).toString();
}
return false;
}); // () => Date.now()
arr.find((item) => {
if (item instanceof Date) {
return item.toString() === new Date('2021/03/04').toString();
}
return false;
}); // Thu Mar 04 2021 00:00:00 GMT+0800
arr.find((item) => {
if (item instanceof RegExp) {
return item.toString() === new RegExp('abc', 'ig').toString();
}
return false;
}); // /abc/gi
// Symbol确实没法比较,只能比较描述是否一样
arr.find((item) => {
if (typeof item === 'symbol') {
return item.toString() === Symbol('sym').toString();
}
return false;
}); // Symbol(sym)
上述判断代码在下面的方法中也会用到。
3.2 比较两个元素
上面我们已经对比了各类元素的对比,所以我们稍微总结一下。
我们先定义一个函数:
const compare = (x, y) => {};
3.2.1 基本类型
对于 、 、 、 null 等基本类型的元素,可以直接进行比较:
const compare = (x, y) => {
return x === y;
};
3.2.2 NaN数据
NaN 用于确定类型,但 NaN 不等于任何数字,包括其本身。
const compare = (x, y) => {
if (typeof x === 'number' && isNaN(x) && typeof y === 'number' && isNaN(y)) {
return true;
}
return x === y;
};
3.2.3 和日期和
对于这些类型,可以将变量转换为字符串进行比较:
const compare = (x, y) => {
if (typeof x === 'number' && isNaN(x) && typeof y === 'number' && isNaN(y)) {
return true;
}
if (
(typeof x === 'function' && typeof y === 'function') ||
(x instanceof Date && y instanceof Date) ||
(x instanceof RegExp && y instanceof RegExp) ||
(x instanceof String && y instanceof String) ||
(x instanceof Number && y instanceof Number)
) {
return x.toString() === y.toString();
}
return x === y;
};
对于类型和数组,我们可以将每一项拆开,然后用上面的方法来一一比较。
3.3 方法
如果我们还想判断数组中是否存在,可以使用()方法。
() 方法返回数组中满足所提供的测试函数的第一个元素的索引。 如果没有找到对应的元素,则返回-1。
arr.findIndex((item) => item === undefined); // 3
arr.findIndex((item) => item === 3); // -1, 没有找到数字3
其他数据格式的判断与上面的find()相同。
一些
some() 方法测试数组中是否至少有 1 个元素通过提供的函数测试。 它返回一个值类型。
注意:如果使用空数组进行测试,则在所有情况下都会返回 false。
some() 方法的使用方式与 find() 方法相同,只不过 some() 方法返回类型数据。
arr.some((item) => item === false); // true
arr.some((item) => item === undefined); // true
arr.some((item) => typeof item === 'number' && isNaN(item)); // true
arr.some((item) => item === 3); // false, 不存在数字3
arr.some((item) => {
if (item instanceof Date) {
return item.toString() === new Date('2021/03/04').toString();
}
return false;
}); // true
() 方法创建一个新数组,其中包含由所提供的函数实现的测试的所有元素。
无论找到多少个元素或者没有找到元素,()方法都会返回一个数组,数组中的数据就是我们想要的元素。
arr.filter((item) => item === false); // 1
arr.filter((item) => item === undefined); // 1
arr.filter((item) => typeof item === 'number' && isNaN(item)); // 1
arr.filter((item) => item === 13); // 2
arr.filter((item) => item === 3); // 0
arr.filter((item) => {
if (item instanceof Date) {
return item.toString() === new Date('2021/03/04').toString();
}
return false;
}); // 1
因此,我们可以通过数组的长度来判断原数组是否包含我们想要的元素。
总结
查找数组中元素的方法有很多种,我们可以根据数组中元素的格式选择更合适的方法。 如果有一些基本类型,建议先使用()方法; 如果格式比较复杂,建议使用some()方法。 两种方法都是直接返回类型,方法的结果可以直接使用,无需进一步转换。