字符串/数组的includes和indexOf细节对比

3,395 阅读5分钟

006APoFYly8gp9idqbnxjg304e04et8s.gif Tips字符串和数组都有includes和indexOf方法,且功能特性基本一致;

本文会先介绍数组的includes和indexOf,随后提一下这两个方法在字符串中有什么不同;

最后拓展一个indexOf的兄弟方法lastIndexOf

相同的功能

两者都是用于判断一个数组中是否存在某个值

不同的返回类型

includes,返回一个 布尔值,存在返回true,不存在则返回false;

indexOf,返回被查找值在数组中 第一次出现的位置下标,不存在则返回-1;

优劣

includes是ES6的语法,语义化更强,可判断是否存在 NaN;

由于indexOf内部使用的严格相等(===)进行判断,所以判断是否存在NaN时始终返回-1; 006APoFYly8gqiccw4k14g308c05qq3b.gif

tips

NaN:(Not-A-Number:不是一个数值数字),他表示的是一个数值范围,而不是一个具体的数值,所以NaN不等于任何值,包括他自己;

[NaN].indexOf(NaN);   // -1
NaN == NaN // false
NaN === NaN  // false ,不等于任何值包括自身

typeOf NaN;    // number,数据类型是Number
NaN+1    // NaN,与任何值进行运算结果都是NaN
Boolean(NaN) // false,转换成布尔值是false

可以用全局方法 isNaN() 来判断,isNaN()方法会调用Number()方法试图将传入的参数转换成数值类型,转换成功返回false,失败就意味着参数不是一个数字,则返回true

于是空字符串和布尔值会被转转成0和1

isNaN(NaN)  // true
isNaN(5)    // false
isNaN('5')   // false
isNaN('A')   // true

Number('')       // 0
Number(true)     // 1
Number(false)    // 1
isNaN('')      // false
isNaN(true)    // false
isNaN(true)    // fasle

注意

ES6提供了 Number.isNaN() 方法来判断一个值本身是否是NaN,不会调用Number()方法对参数进行转换,只有在参数是值为 NaN 的数字时,才会返回 true

Number.isNaN('123')   // false 本身不是NaN
Number.isNaN('abc'// false 本身不是NaN

Number.isNaN(NaN)         // true
Number.isNaN(Number.NaN); // true
Number.isNaN(0 / 0)       // true

细节对比

const arr = ['a', 'b', 'b', '2', 0, NaN,3]

// 查找值存在时,indexOf 返回该值的下标,includes 返回true
arr.indexOf('a')    // 0
arr.includes('a')   // true

// 查找值不存在时,indexOf返回 -1,includes返回false
arr.indexOf('c')    // -1
arr.includes('c')   //false

// 查找值在数组中出现多次时,indexOf返回第一次出现的位置下标,includes返回true
arr.indexOf('b')    // 1
arr.includes('b')   // true

// 都是严格比较,值和类型都要相等,且区分大小写,不区分+0和-0
arr.indexOf(2)    // -1
arr.includes(2)   // false

arr.indexOf('A')    // -1
arr.includes('A')   // false

arr.indexOf(+0)    // 4
arr.indexOf(-0)    // 4
arr.includes(+0)   // true
arr.includes(-0)   // true

// indexOf不能正确判断是否存在NaN,includes可以
arr.indexOf(NaN)    // -1
arr.includes(NaN)   // true

ceeb653ely8gw59g51kf8g206i05kaa9.gif

可选的第二参数

两者的第二个参数都是查找的起始下标

查找值在数组中但不在起始范围内则判断为不存在

const arr = ['a', 'b', 'b', '2', 0, NaN,3]

arr.indexOf('a',0)    // 0
arr.includes('a',0)   // true
arr.indexOf('a',1)    // -1
arr.includes('a', 1)   // false

// 起始下标大于等于数组长度时,不查找,直接判断为不存在
arr.indexOf(3,7)    // -1
arr.includes(3, 7)   // false

// 起始下标为负数时,表示从数组的倒数第几个开始查找
// 但查找顺序不变,依旧是从左往右 从前往后
// 如果负值的绝对值大于数组长度,起始下标重置成0,查找整个数组
arr.indexOf(3,-1)    // 6,从倒数第一个开始从左往右找
arr.includes(3, -1)   // true

arr.indexOf(0,-2)    // -1,从倒数第二个开始从左往右找
arr.includes(0, -2)   // false

arr.indexOf(0,-8)    // 4,绝对值大于数组长度则整个数组都查找
arr.includes(0, -8)   // true

字符串的indexOf和includes方法

在字符串中这两个方法的特性和数组基本一致,不一样的地方有一下几点

字符串的indexOf第一个参数如果不传,则会被强制设置成 "undefined"

const str = 'undefined'
const arr = ['undefined','a']
str.indexOf()   // 0
str.indexOf('')   // 0
arr.indexOf()   // -1

字符串的indexOf第二个参数如果为负数则重置为0

const str = 'abcd'
const arr=['a','b','c','d']
str.indexOf('b', -2) // 1,从下标0开始查找
arr.indexOf('b',-2) // false,从倒数第二个开始查找

另外存在一个怪异的现象,这里直接贴MDN,详情去MDN查看👉🏻点击跳转👈🏻

image.png

lastIndexOf

功能描述 lastIndexOf返回被查找值在数组或字符串中最后出现位置的下标

也是数组和字符串都有的方法,这里依旧先以数组为例

不同点 既然是返回被查找值最后出现的位置,那么自然是从后往前找效率会更高些;

第一个参数是要查找的值,第二个参数是开始反向查找的下标,默认是数组长度减一(arr.length-1)

如果第二个参数大于或等于数组的长度,则查找整个数组

const arr = ['a', 'b', 'c', 'b', 'd']
const str = 'abcbd'

arr.lastIndexOf('b')    // 3,默认从最后一个元素d开始,从右往左找
str.lastIndexOf('b')    // 3

arr.lastIndexOf('b', 2)    // 1,从下标2也就是c开始,从右往左找
str.lastIndexOf('b', 2)    // 1

arr.lastIndexOf('b', 5)    // 3,当第二个参数大于等于数组长度时,就从数组最后一位开始,从右往左找
arr.lastIndexOf('b', 10)   // 3

str.lastIndexOf('b', 5)     // 3
str.lastIndexOf('b', 10)    // 3

// 如果是负数,表示从倒数的第几个元素开始,从右往左找
// 注意,+0、-0都视为 0,不存在倒数第0个,0就是从第一个开始
// 如果负值的绝对值大于数组的长度,则直接返回 -1
arr.lastIndexOf('b', -2)     // 3,从数组倒数第二项开始,从右往左找
arr.lastIndexOf('b', -10)    // -1,绝对值大于数组长度,直接返回 -1

arr.lastIndexOf('b', 0)     // -1,从数组第一项开始,从右往左找
arr.lastIndexOf('a', 0)     // 0



// 字符串的第一参数,如果是空字符串就返回被查字符串的长度
str.lastIndexOf('')         // 5

// 字符串的第二个参数默认值是 +Infinity(正无穷)
// 如果大于等于字符串长度,则从字符串最后一位开始,从右往左找完
// 如果为负数,则重置为 0,从字符串的第一项开始,从右往左
str.lastIndexOf('a', -2)     // 0
str.lastIndexOf('b', -2)    // -1

str.lastIndexOf('a', 0)     // 0
str.lastIndexOf('b', 0)     // -1

// 字符串匹配完整字符,匹配成功时返回匹配的第一个字符下标
const str2 = 'abcbabc'
str2.lastIndexOf('ab')  // 4,从最后一个字符往左匹配
str2.lastIndexOf('ab', 4)  // 4,从下标为4的字符开始往左匹配,由于要匹配的是两个字符,
// 所以会把下标为5的字符加入匹配,匹配成功返回下标4
str2.lastIndexOf('abc', 4)      // 4

如有错误请指正~