前言

在前端开发中,经常会遇到要判断数组中是否存在某个元素。其实判断的方式有很多种,我们一个一个来了解下。

我们先来定义一个数组:

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'),
];

在这个数组中,我们包含了好几种类型:number, boolean, string, undefined, null, array, object, Date, Symbol 等。其中数字 13 出现了 2 次。

有备而来

1. indexOf

我们最熟悉的就是indexOf了,毕竟他出现的早,兼容性也好,使用起来也很方便。

如果存在该元素,则返回第一次出现的索引值;若整个数组不存在该元素,则返回-1。

1.1 使用方式

只要判断返回的数据是不是-1,就能知道数组中是否包含该元素。

arr.indexOf(13) >= 0; // true, indexOf返回0
arr.indexOf(2) >= 0; // false, indexOf返回-1

与 indexOf 对应的是 lastIndexOf,从最后往前查找元素,若存在该元素,则返回在数组中的最后一个的索引;若不存在该元素,则返回-1。

arr.lastIndexOf(13) >= 0; // true, lastIndexOf返回4, 最后一次出现的索引

两个方法在判断变量是否存在时,调用方式是一样的。

1.2 第 2 个可选参数

indexOf 和 lastIndexOf 还有第 2 个可选参数 fromIndex,用来表示从哪个索引开始进行搜索。

在 indexOf 中,若 fromIndex 超过数组的长度,则直接返回-1,若为负数,则从最后往前数几个索引(arr.length-Math.abs(fromIndex)),然后开始往后搜索。

在 lastIndexOf 中,若 fromIndex 达到或超过数组的长度,则搜索整个数组;若为负数,则从最后往前数几个索引(arr.length-Math.abs(fromIndex)),然后开始往前搜索,若负数的绝对值超过了数组的长度,则直接返回-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)开始往前搜索

而且 indexOf 和 lastIndexOf 中采用的是严格相等的方式(===)来判断的。

arr.indexOf(null); // 5, 在null的前面有几个假值false和undefined,也能准确找到null的索引值
瑟瑟发抖

2. includes

indexOf 主要是为了查找元素所在的索引值,只是我们可以用返回的索引值来间接判断数组中是否存在该元素。

而在 ES7(ES2016)中添加的includes方法,就是专门用来判断元素是否存在的。返回值为 true 或者 false,true 表示存在,false 表示不存在,简单明了。

arr.includes(13); // true
arr.includes('abc'); // false
arr.includes(false); // true, 存在false元素

同时,includes 方法中也存在第 2 个可选参数 fromIndex,fromIndex 的用法与 indexOf 中的一样。若 fromIndex 超过数组的长度,则直接返回-1,若为负数,则从最后往前数几个索引(arr.length-Math.abs(fromIndex)),然后开始往后搜索。

arr.includes(13, 5); // false, 从索引值5开始往后检索,没检索到

到目前为止,后面的几种类型,例如 Array, Object, Date 和 Symbol,我们都没判断呢。我们现在来判断下后面的几个元素:

// 使用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

结局很惨,这几种元素在数组中都没有检索到。可是实际上在数组中都是真实存在的。

这是因为 indexOf 和 includes 都是采用严格相等的方式(===)来判定的。

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类型的出现就是为了避免冲突创造出来的类型,括号里的属性仅是为了方便描述而已

针对这些无法被检索的类型,我们就需要自己写函数来判断特殊的类型了。

3. find 和 findIndex

find()和 findIndex()允许我们通过回调函数,来自定义判断的方式。

3.1 find 方法

find() 方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined。

find()方法无法检测数组中的 undefined 元素。

因为不存在和存在 undefined 元素,find()方法都会返回 undefined。这里我们就要考虑其他方式了,稍后再讲。

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 基本类型

对于元素是 string, number, boolean, undefined, null 等基本类型的,可以直接进行比较:

const compare = (x, y) => {
 return x === y;
};

3.2.2 NaN 数据

NaN 用 typeof 来判断是 number 类型,但 NaN 不与任何数字相等,包括它自己。

const compare = (x, y) => {
 if (typeof x === 'number' && isNaN(x) && typeof y === 'number' && isNaN(y)) {
  return true;
 }
 return x === y;
};

3.2.3 Function 与 Date 与 RegExp

这些类型的,可以将变量转为字符串进行比较:

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;
};

对于 object 类型和 array 的,我们可以将每一项拆开,然后利用上面的方式再挨个儿比较。

3.3 findIndex 方法

如果还要判断数组中是否存在 undefined,我们可以使用findIndex()方法。

findIndex() 方法返回数组中满足提供的测试函数的第一个元素的索引。若没有找到对应元素则返回-1。

arr.findIndex((item) => item === undefined); // 3
arr.findIndex((item) => item === 3); // -1, 没有找到数字3

其他数据格式的判断,与上面的 find()一样。

稀客呀

4. some

some() 方法测试数组中是不是至少有 1 个元素通过了被提供的函数测试。它返回的是一个 Boolean 类型的值。

注意:如果用一个空数组进行测试,在任何情况下它返回的都是 false。

some()方法与 find()方法的使用方式一样,只不过 some()方法返回的是 boolean 类型的数据。

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

5. filter

filter() 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。

无论找到几个元素或者没有元素,filter()方法都是会返回一个数组,数组中的数据就是我们想要的元素。

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

因此我们可以通过该数组的长度,来判断原数组是否包含我们想要的元素。

略略

6. 总结

查找数组中元素的方式有很多,我们可以数组中元素的格式,来选择更合适的方式。如果都是一些基本类型,建议优先选择使用includes()方法;如果格式比较复杂的,建议选择使用some()方法。这两个方法都是直接返回 boolean 类型,无需更多的转换即可直接使用方法的结果。

到此这篇关于利用JS十分钟判断数组中存在元素的多种方式的文章就介绍到这了,更多相关JS判断数组存在元素内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

利用JS十分钟判断数组中存在元素的多种方式的更多相关文章

  1. html5使用canvas实现弹幕功能示例

    这篇文章主要介绍了html5使用canvas实现弹幕功能示例的相关资料,需要的朋友可以参考下

  2. 前端实现弹幕效果的方法总结(包含css3和canvas的实现方式)

    这篇文章主要介绍了前端实现弹幕效果的方法总结(包含css3和canvas的实现方式)的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  3. H5 canvas实现贪吃蛇小游戏

    本篇文章主要介绍了H5 canvas实现贪吃蛇小游戏,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  4. ios – parse.com用于键,预期字符串的无效类型,但是得到了数组

    我尝试将我的数据保存到parse.com.我已经预先在parse.com上创建了一个名为’SomeClass’的类.它有一个名为’mySpecialColumn’的列,其数据类型为String.这是我尝试使用以下代码保存数据的代码:如果我运行这个我得到:错误:密钥mySpecialColumn的无效类型,预期字符串,但得到数组这就是我在parse.com上的核心外观:有谁知道我为什么会收到这个错误?

  5. ios – 上下文类型’NSFastEnumeration’不能与数组文字一起使用

    斯威夫特3,你会这样做吗?解决方法正如您所发现的,您不能使用as-casting将数组文字的类型指定为NSFastEnumeration.您需要找到一个符合NSFastEnumeration的正确类,在您的情况下它是NSArray.通常写这样的东西:

  6. ios – 获取资产目录文件夹中所有图像的数组

    在iOS中,是否可以获取资产目录文件夹中的图像数组?我不确定为什么会对此进行投票.我真的不知道从哪里开始.我的另一种方法是创建文件夹中所有文件的plist,但它似乎是多余的.我无法添加任何代码,因为我会添加什么?

  7. ios – 来自调试器的消息:由于内存问题而终止

    我的应用程序使用Geojson文件.我使用MapBoxSDK将MGLpolyline添加到地图中.但问题是我的文件太大,以至于应用程序崩溃并收到错误:来自调试器的消息:由于内存问题而终止.我在第一次循环时面对66234个对象.我试图将数组块化为新数组,但没有成功.请帮我解决问题.这是我在地图上绘制的代码,这里是我的testprojectongithubuseXcode8.1如果有任何不同的第三方可

  8. ios – Swift – 使用字典数组从字典访问数据时出错

    我有一个非常简单的例子,说明我想做什么基本上,我有一个字典,其值包含[String:String]字典数组.我把数据填入其中,但当我去访问数据时,我收到此错误:Cannotsubscriptavalueoftype‘[([String:String])]?’withanindexoftype‘Int’请让我知道我做错了什么.解决方法您的常量数组是可选的.订阅字典总是返回一个可选项.你必须打开它.更

  9. ios – 在Swift中使用“Map”创建两个数组的超集

    假设我有两个数组:我想组合两个数组,以便我得到一个输出我该怎么做呢?

  10. ios – 基于一个对象内的一个值,根据一个值对NSObject数组进行排序

    我创建了一个对象,它看起来像这样然后将其添加到可变数组.稍后,我计算出每个对象到当前gps位置的距离,并将其添加到对象中并将其放回到数组中.我现在需要根据aOffice.distance的值对该数组进行排序,但不知道该怎么做请有人帮帮我谢谢解决方法

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部