ES2016系列: Array.prototype.includes
发布于 9 年前 作者 zhangmingkai4315 3747 次浏览 最后一次编辑是 8 年前 来自 分享

本篇文章主要是介绍ES2016(ES7)的其中一个数组特性includes,通过实例来对比一下该函数与indexOf的区别以及如何使用es5来实现该特性。

函数介绍

Array.prototype.includes是在ES2016版本中被引入的一个数组函数,该函数允许我们查询一个对象是否被包含在数组中,可能我们经常使用的传统的方式是indexOf来查询,indexOf通过返回值是否等于-1来获得查询对象是否被该数组包含。而includes则是通过返回true或者false来得出结果,对于只是查询是否包含,语义显得更清晰一些。

var boolean = array.includes(searchElement[, fromIndex])

参数列表: searchElement:搜索的对象内容。fromIndex:可选参数,类似于indexOf的第二个参数,指定搜素开始的位置,缺省为0。

函数实例

如果仅仅是与indexOf返回值略有不同,好像存在的意义也不大。但是通过includes具有一些新的比较规则,我们通过以下的实例来介绍以下。 以下实例均可以在最新的chrome,firefox浏览器中测试。

[1,2,3].includes(2)
true
[1,2,3].includes(4)
false
[1,2,3].includes(3,3)
false
[1,2,3].includes(3,2)
true
[1,2,NaN].includes(NaN)
true	

大家可以看到我们可以通过includes来测试一个数组中是否包含NaN,这样的比较如果使用indexOf则返回

[1,2,NaN].indexOf(NaN)
-1

可见函数实现上includes进行了一些深度的测试与比较,包含了NaN对象的判定。

函数实现

如果在浏览器环境中我们想使用该函数的话,最好是写一些Polyfill来检测浏览器的支持程度,对于不支持的浏览器我们需要实现该函数,以备后面的程序中使用。MDN上已经对于该函数做了实现,如下面代码所示。

if (!Array.prototype.includes) {
  Array.prototype.includes = function(searchElement /*, fromIndex*/ ) {
    'use strict';
    var O = Object(this);
    var len = parseInt(O.length) || 0;
    if (len === 0) {
      return false;
    }
    var n = parseInt(arguments[1]) || 0;
    var k;
    if (n >= 0) {
      k = n;
    } else {
      k = len + n;
      if (k < 0) {k = 0;}
    }
    var currentElement;
    while (k < len) {
      currentElement = O[k];
      if (searchElement === currentElement ||
         (searchElement !== searchElement && currentElement !== currentElement)) { // NaN !== NaN
        return true;
      }
      k++;
    }
    return false;
  };
}

实现介绍:

  1. 首先判断该函数是否存在,对于不存在的情况我们定义了一个自己的function函数

  2. 将调用的对象this保存到变量0中,并将length保存在变量len中。

  3. 判断是否具有两个参数,如果参数2存在(起始位置参数)则将其保存在k中,对于负数我们从尾部开始计算(逆向)。

  4. 进入循环判定,其中这里最关键的是对于对象的比较,为了实现NaN的比较我们加入了一段新的判断代码

    searchElement !== searchElement && currentElement !== currentElement

对于NaN,我们知道NaN !== NaN 所有我们的判断中对于自身进行了判断,如果自己不等于自己 则肯定为NaN。

加入新的判定后,会对于实现的效率有所降低。以下我们选择的是100万次的比较,对于正常的使用,函数的性能不会影响太大。

var indexOfTime=function(){
	var begin=new Date().getTime();
    for(var i=0;i<1000000;i++) {
    	[1,2,3].indexOf(4)
    } 
   console.log((new Date().getTime())-begin);
}


var includesTime=function(){
	var begin=new Date().getTime();
    for(var i=0;i<1000000;i++) {
    	[1,2,3].includes(4)
    } 
   console.log((new Date().getTime())-begin);
}

indexOfTime()
VM7330:6 34

indexOfTime()
VM7330:6 20

includesTime()
VM7396:6 167

includesTime()
VM7396:6 190

总结

Array.prototype.includes在实现上并非扩展了原有的indexOf 因为并未返回检索位置信息,只是单纯的返回一个查询的bool值。但是增加了对于NaN的支持,使得查询更加的全面。原文放置在个人Blog上欢迎大家访问jsmean.com,后期我也会增加一些新的内容,欢迎大家一起学习讨论。

回到顶部