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;

  };

}

 

posted @ 2020-05-28 21:08  baclona  阅读(519)  评论(0)    收藏  举报