博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
有了 indexOf,为什么 ECMAScript 7 还添加了 Array.prototype.include
阅读量:5270 次
发布时间:2019-06-14

本文共 3237 字,大约阅读时间需要 10 分钟。

ECMAScript 7 中新增了用于检测数组中是否包含某个元素 Array.prototype.includes() API,想到了 Array 其实有很多相关 API 可以检测到是否包含某个元素,比如 Array.prototype.indexOf,于是好奇为什么要实现这样一个 "看起来功能有点重复的 API"。

前端开发 QQ 群:377786580

原文发表于 ,转载请参阅 。

前言

最近又看了下 ECMAScript 7 规范,看到新的规范中包含 Array.prototype.includes(),方法签名如下:

Array.prototype.includes(value : any): boolean

Array.prototype.includes() 是用于检测数组中是否包含某个元素。

[0, 1].includes(1) // true['foo', 'bar'].includes('baz') // false

想到了 Array 其实有很多相关 API 可以检测到是否包含某个元素:

[0, 1].findIndex(i => i == 1) // 1['foo', 'baz'].find(i => i == 'foo') // foo['foo', 'baz'].indexOf('foo') // 0
  • Array.prototype.findIndex():返回数组中满足提供的测试函数的第一个元素的索引。否则返回 -1
  • Array.prototype.find():返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined
  • Array.prototype.indexOf():返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回 -1

我们可以简单的通过判断实现类似 Array.prototype.includes() 的效果:

export const includes = (sources : any[] searchElement: any): boolean => {    return !!~any.indexOf(searchElement)}

于是好奇为什么要实现这样一个 "看起来功能有点重复的 API"。

查询了 StackOverflow 和 TC39 (Technical Committee 39,JavaScript 委员会) 的 ,找到一些细节。

Array.prototype.includes 前身

早前的 Array.prototype.includes 的提案名为 Array.prototype.contains,但由于有很多网站自行 hack 了 Array.prototype.contains(其实主要是因为 ),看起来就跟上面的代码类似。

JavaScript 中所有原生提供的方法属性都是 不可枚举的( enumerable ) 的,我们可以通过 Object.getOwnPropertyDescriptor(object: any, prototypeName : String) 来获取这个属性的属性描述符 (Property Descriptor)。

Object.getOwnPropertyDescriptor(Array.prototype, 'indexOf')// output { writable: true, enumerable: false, configurable: true, value: ƒ() }

给对象赋值,是不会改变原属性的属性描述符,我们可以给 Array.prototype.indexOf 重新赋值,之后获取它的属性描述符,会发现 indexOf 仍是不可枚举的:

Array.prototype.indexOf = () => { return -1 }Object.getOwnPropertyDescriptor(Array.prototype, 'indexOf')// output { writable: true, enumerable: false, configurable: true, value: ƒ() }

而这些网站自行 hackcontains() 是可以被枚举的,也就是可以通过 for..in 读出来。

发现问题了么?

如果规范实现 contains(),会导致 contains() 无法被 for..in 读出来,而之前自行 hackcontains() 是可以被读出来的,所以会出现代码没变动,但是在新规范推出后会产生 bug 的情况。

Array.prototype.contains 初稿阶段,考虑到新的规范不能让世界上许多现有的网站出问题,所以改名成了 Array.prototype.includes

细节

起源

虽然我们可以使用 indexOf() 来模拟 includes() 的行为,但是 indexOf() 在语义上无法清晰的描述这个场景。

includes() 是明确的判断 "是否包含该项",而 indexOf() 是 "查找数组中第一次出现对应元素的索引是什么,再针对返回的索引进一步处理逻辑",例如下面的代码:

// indexOfif (~arr.indexOf(1)) {    // do something}// includesif (arr.includes(1)) {    // do something}

为什么叫做 includes 而不是 has

has 是用于 key 的,而 includes 是检测 value 的:

let foo = new Map()foo.set('name', 'linkFly')foo.has('name') // true

SameValueZero

Array.prototype.includes 底层使用了 进行元素比较。

目前 ES2015 草案中有四种相等算法:

  • :实现接口是 == 运算符
  • :实现接口是 === 运算符,Array.prototype.indexOf 就是使用这种比较
  • :没有直接暴露的接口,内部实现接口是 MapSet

    const foo = new Map()foo.set(0, '0') // Map(1) {0 => "0"}foo.set('0', 'zero') // Map(2) {0 => "0", "0" => "zero"}foo.get(0) // 0foo.get('0') // zero
  • :实现接口是 Object.is()

    ```typescript
    NaN === NaN // false
    Object.is(NaN, NaN) // true

    -0 === +0 // true

    Object.is(-0, +0) // false
    ```

SameValue() 不同的是,SameValueZero() 不区分 +0-0。而 includes 所以内部也采用了 SameValueZero 实现。

所以 Array.prototype.includes 也不区分 +0-0 ,当然也可以检测 NaN

[-0].includes(+0) // true[NaN].includes(NaN) // true[NaN].indexOf(NaN) // -1

具体的相等比较运算符差异请参阅 。

具体 Array.prototype.includes 实现的细节可以参考 ecma-262/ECMAScript 7

参考和引用

转载于:https://www.cnblogs.com/silin6/p/Array-prototype-include.html

你可能感兴趣的文章
SSH框架整合配置所需JAR包(SSH整合)
查看>>
PHP函数
查看>>
html5多媒体Video/Audio
查看>>
如何安装windows7
查看>>
[主席树]HDOJ4348 To the moon
查看>>
shell脚本统计文件中单词的个数
查看>>
SPCE061A学习笔记
查看>>
sql 函数
查看>>
hdu 2807 The Shortest Path 矩阵
查看>>
熟悉项目需求,要知道产品增删修改了哪些内容,才会更快更准确的在该项目入手。...
查看>>
JavaScript 变量
查看>>
java实用类
查看>>
mysql 主从库同步
查看>>
smarty模板自定义变量
查看>>
研究称90%的癌症由非健康生活习惯导致
查看>>
命令行启动Win7系统操作部分功能
查看>>
ABP入门系列(6)——定义导航菜单
查看>>
排序sort (一)
查看>>
Intent应用
查看>>
暑假周报告总结第二周
查看>>