indexOf底层研究
在开始研究之前,咱们先来回答两问题:
第一个问题:
const arr1 = [1,2,3,4,5];
const arr2 = ['1','2','3','4','5'];
arr1.indexOf('1') // 输出什么
arr2.indexOf(1) // 输出什么
第二个问题:
const arr = ['a','b','c'];
const str = 'abc';
arr.indexOf('b') // 输出什么
str.indexOf('b') // 输出什么
这两个indexOf用法是否一模一样?
带着这两个问题,开始咱们今天的研究。
研究某一个方法,最有说服力的就是官网。让我们来看一看mozilla上是怎么说的。


个人的理解就是:
indexOf返回数组或字符中,找到的第一个给定值的索引。如果不存在,就返回-1;
我们把indexOf的官方Polyfill代码拿来,一行一行的分析,前面两个问题的答案迎刃而解。
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function(searchElement, fromIndex) {
var k;
// this也就是indexOf的调用体,如果连调用体都不存在的话,当然在抛错
if (this == null) {
throw new TypeError('"this" is null or not defined');
}
var O = Object(this); // 这段代码的信息量比较大,这里只是简单说明一下,后面我会专心写一篇来介绍数据类型的文章
为什么这里要用Object包一层,如果不包的话,会有什么影响?这里要从js6种基本数据类型说起。
我们知道,js有6种基本数据类型:undefined,null,boolean,number,string,symbol。还有两种最常用的引用数据类型Object,array。(还有一些引用类型,因为我还没有研究,所以这里不写了。大神请指教)
让我们来分别将这些类型包装进Object,看看会发生什么?
Object(undefined)

Object(null)

Object(true)

Object(false)

Object('111')

Object(111)

Object({a: 1})

Object([1,2,3,4])

你会发现,只有number和sring类型,被Object包装之后,有length属性。
这也就回答了上面的第二个问题:IndexOf可以用于array和string,而且他们两个的用法和返回值是一模一样的。
调用体用Object包一层,其实是就做了容错。Object(数据类型).length要么返回undefined,要么返回具体长度,而不至于报错。
也可以这么理解,任务类型通过Object()包装,等同事通过new 的方式,通过实例化的方式声明一个变量。
// 通过位运算,对O.length进行无符号右移。


因为undefined >>> 0 = 0;null >>> 0 = 0;0 >>> 0 = 0;
所以,如果O有length属性,比如array和string(通过上面的截图也能找到),O.length会返回正确的结果。如果O没有length属性,比如boolean object等,则会返回0;
var len = O.length >>> 0;
if (len === 0) {
return -1;
}
这段代码就等价于,如果调用体不是string或array,则直接返回-1,后面的代码不执行。
var len = O.length >>> 0;
if (len === 0) {
return -1;
}
// 进行一次类型转换,用一个+号对formIndex进行转义。我个人比较喜欢使用Number
var n = +fromIndex || 0;
// 容错 略过
if (Math.abs(n) === Infinity) {
n = 0;
}
// n不能大于len,否则没有意义
if (n >= len) {
return -1;
}
// 进行多情景处理
k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
while (k < len) {
if (k in O && O[k] === searchElement) {
return k;
// 这里要研究一下判断条件
因为O是经过Object包装的,即O被转化为了Object类型。所以k in O 和O[k]是成立的。

比如Object('aa')的结果,可以理解为
{
0: 'a',
1: 'a',
length: 2
}
从“ O[k] === searchElement”可以看出,indexOf(param)中的参数与调用体进行的全等比较,也就回答了第一个问题。
const arr1 = [1,2,3,4,5];
const arr2 = ['1','2','3','4','5'];
arr1.indexOf('1') // 输出-1
arr2.indexOf(1) // 输出-1
因为他们的类型都不一样
}
k++;
}
return -1;
};
}

浙公网安备 33010602011771号