摘要:前端開(kāi)發(fā)群原文發(fā)表于,轉(zhuǎn)載請(qǐng)參閱轉(zhuǎn)載授權(quán)。查詢(xún)了和,委員會(huì)的提案,找到一些細(xì)節(jié)。前身早前的的提案名為,但由于有很多網(wǎng)站自行了其實(shí)主要是因?yàn)閷?dǎo)致的,看起來(lái)就跟上面的代碼類(lèi)似。而為了和其他特性保持一致所以?xún)?nèi)部也采用了實(shí)現(xiàn)。
ECMAScript 7 中新增了用于檢測(cè)數(shù)組中是否包含某個(gè)元素 Array.prototype.includes() API,想到了 Array 其實(shí)有很多相關(guān) API 可以檢測(cè)到是否包含某個(gè)元素,比如 Array.prototype.indexOf,于是好奇為什么要實(shí)現(xiàn)這樣一個(gè) "看起來(lái)功能有點(diǎn)重復(fù)的 API"。
前端開(kāi)發(fā) QQ 群:377786580
原文發(fā)表于 http://tasaid.com,轉(zhuǎn)載請(qǐng)參閱 轉(zhuǎn)載授權(quán)。
前言最近又看了下 ECMAScript 7 規(guī)范,看到新的規(guī)范中包含 Array.prototype.includes(),方法簽名如下:
Array.prototype.includes(value : any): boolean
Array.prototype.includes() 是用于檢測(cè)數(shù)組中是否包含某個(gè)元素。
[0, 1].includes(1) // true ["foo", "bar"].includes("baz") // false
想到了 Array 其實(shí)有很多相關(guān) API 可以檢測(cè)到是否包含某個(gè)元素:
[0, 1].findIndex(i => i == 1) // 1 ["foo", "baz"].find(i => i == "foo") // foo ["foo", "baz"].indexOf("foo") // 0
Array.prototype.findIndex():返回?cái)?shù)組中滿(mǎn)足提供的測(cè)試函數(shù)的第一個(gè)元素的索引。否則返回 -1
Array.prototype.find():返回?cái)?shù)組中滿(mǎn)足提供的測(cè)試函數(shù)的第一個(gè)元素的值。否則返回 undefined
Array.prototype.indexOf():返回在數(shù)組中可以找到一個(gè)給定元素的第一個(gè)索引,如果不存在,則返回 -1
我們可以簡(jiǎn)單的通過(guò)判斷實(shí)現(xiàn)類(lèi)似 Array.prototype.includes() 的效果:
export const includes = (sources : any[] searchElement: any): boolean => { return !!~any.indexOf(searchElement) }
于是好奇為什么要實(shí)現(xiàn)這樣一個(gè) "看起來(lái)功能有點(diǎn)重復(fù)的 API"。
查詢(xún)了 StackOverflow 和 TC39 (Technical Committee 39,JavaScript 委員會(huì)) 的 ECMAScript 提案,找到一些細(xì)節(jié)。
Array.prototype.includes 前身早前的 Array.prototype.includes 的提案名為 Array.prototype.contains,但由于有很多網(wǎng)站自行 hack 了 Array.prototype.contains(其實(shí)主要是因?yàn)?MooTools 導(dǎo)致的),看起來(lái)就跟上面的代碼類(lèi)似。
JavaScript 中所有原生提供的方法屬性都是 不可枚舉的( enumerable ) 的,我們可以通過(guò) Object.getOwnPropertyDescriptor(object: any, prototypeName : String) 來(lái)獲取這個(gè)屬性的屬性描述符 (Property Descriptor)。
Object.getOwnPropertyDescriptor(Array.prototype, "indexOf") // output { writable: true, enumerable: false, configurable: true, value: ?() }
給對(duì)象賦值,是不會(huì)改變?cè)瓕傩缘膶傩悦枋龇覀兛梢越o Array.prototype.indexOf 重新賦值,之后獲取它的屬性描述符,會(huì)發(fā)現(xiàn) indexOf 仍是不可枚舉的:
Array.prototype.indexOf = () => { return -1 } Object.getOwnPropertyDescriptor(Array.prototype, "indexOf") // output { writable: true, enumerable: false, configurable: true, value: ?() }
而這些網(wǎng)站自行 hack 的 contains() 是可以被枚舉的,也就是可以通過(guò) for..in 讀出來(lái)。
發(fā)現(xiàn)問(wèn)題了么?
如果規(guī)范實(shí)現(xiàn) contains(),會(huì)導(dǎo)致 contains() 無(wú)法被 for..in 讀出來(lái),而之前自行 hack 的 contains() 是可以被讀出來(lái)的,所以會(huì)出現(xiàn)代碼沒(méi)變動(dòng),但是在新規(guī)范推出后會(huì)產(chǎn)生 bug 的情況。
在 Array.prototype.contains 初稿階段,考慮到新的規(guī)范不能讓世界上許多現(xiàn)有的網(wǎng)站出問(wèn)題,所以改名成了 Array.prototype.includes。
細(xì)節(jié) 起源雖然我們可以使用 indexOf() 來(lái)模擬 includes() 的行為,但是 indexOf() 在語(yǔ)義上無(wú)法清晰的描述這個(gè)場(chǎng)景。
includes() 是明確的判斷 "是否包含該項(xiàng)",而 indexOf() 是 "查找數(shù)組中第一次出現(xiàn)對(duì)應(yīng)元素的索引是什么,再針對(duì)返回的索引進(jìn)一步處理邏輯",例如下面的代碼:
// indexOf if (~arr.indexOf(1)) { // do something } // includes if (arr.includes(1)) { // do something }為什么叫做 includes 而不是 has
has 是用于 key 的,而 includes 是檢測(cè) value 的:
let foo = new Map() foo.set("name", "linkFly") foo.has("name") // trueSameValueZero
Array.prototype.includes 底層使用了 SameValueZero() 進(jìn)行元素比較。
目前 ES2015 草案中有四種相等算法:
抽象標(biāo)準(zhǔn)相等比較:實(shí)現(xiàn)接口是 == 運(yùn)算符
嚴(yán)格相等比較:實(shí)現(xiàn)接口是 === 運(yùn)算符,Array.prototype.indexOf 就是使用這種比較
SameValueZero():沒(méi)有直接暴露的接口,內(nèi)部實(shí)現(xiàn)接口是 Map 與 Set
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) // 0 foo.get("0") // zero
SameValue():實(shí)現(xiàn)接口是 Object.is()
NaN === NaN // false Object.is(NaN, NaN) // true -0 === +0 // true Object.is(-0, +0) // false
和 SameValue() 不同的是,SameValueZero() 不區(qū)分 +0 和 -0。而 includes 為了和 JavaScript 其他特性保持一致 所以?xún)?nèi)部也采用了 SameValueZero 實(shí)現(xiàn)。
所以 Array.prototype.includes 也不區(qū)分 +0 和 -0 ,當(dāng)然也可以檢測(cè) NaN:
[-0].includes(+0) // true [NaN].includes(NaN) // true [NaN].indexOf(NaN) // -1
具體的相等比較運(yùn)算符差異請(qǐng)參閱 MDN - Equality comparisons and sameness。
具體 Array.prototype.includes 實(shí)現(xiàn)的細(xì)節(jié)可以參考 ecma-262/ECMAScript 7 實(shí)現(xiàn)規(guī)范。
參考和引用tc39 - Array.prototype.includes Proposal
Having a non-enumerable Array.prototype.contains may not be web-compatible
ECMAScript? 2016 Language Specification - Array.prototype.includes
ECMAScript? 2015 Language Specification - SameValueZero
stackoverflow - How do I check if an array includes an object in JavaScript?
http://2ality.com/2016/02/array-prototype-includes.html
Bugzilla@Mozilla - non-enumerable Array.prototype.contains is not web-compatible (breaks jsfiddle.net)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/85023.html
摘要:寫(xiě)的姿勢(shì)前兩天去帝都參加第三屆前端開(kāi)發(fā)者大會(huì),見(jiàn)了很多老朋友,也認(rèn)識(shí)了很多新朋友。 推薦 1. 組件化設(shè)計(jì)思維 – 從規(guī)范到工具的構(gòu)建與探索 http://www.zcool.com.cn/artic... 阿里巴巴在中臺(tái)戰(zhàn)略的背景下,設(shè)計(jì)提效又再次推動(dòng)著設(shè)計(jì)思維的變革。設(shè)計(jì)師們不僅僅需要出色地完成業(yè)務(wù)需求的設(shè)計(jì),同時(shí)還需要思考設(shè)計(jì)的價(jià)值,也就是經(jīng)常提到的最佳方案性?xún)r(jià)比。我們需要在設(shè)計(jì)...
摘要:寫(xiě)的姿勢(shì)前兩天去帝都參加第三屆前端開(kāi)發(fā)者大會(huì),見(jiàn)了很多老朋友,也認(rèn)識(shí)了很多新朋友。 推薦 1. 組件化設(shè)計(jì)思維 – 從規(guī)范到工具的構(gòu)建與探索 http://www.zcool.com.cn/artic... 阿里巴巴在中臺(tái)戰(zhàn)略的背景下,設(shè)計(jì)提效又再次推動(dòng)著設(shè)計(jì)思維的變革。設(shè)計(jì)師們不僅僅需要出色地完成業(yè)務(wù)需求的設(shè)計(jì),同時(shí)還需要思考設(shè)計(jì)的價(jià)值,也就是經(jīng)常提到的最佳方案性?xún)r(jià)比。我們需要在設(shè)計(jì)...
摘要:由于網(wǎng)景公司希望能在靜態(tài)頁(yè)面上添加一些動(dòng)態(tài)效果,于是叫這哥們?cè)趦芍苤畠?nèi)設(shè)計(jì)出了語(yǔ)言。所以簡(jiǎn)單說(shuō)來(lái)就是,是一種語(yǔ)言標(biāo)準(zhǔn),而是網(wǎng)景公司對(duì)標(biāo)準(zhǔn)的一種實(shí)現(xiàn)。 JavaScript基礎(chǔ)拾遺 study notes by Tingting 為啥說(shuō)JavaScript的基礎(chǔ) 在平時(shí)開(kāi)發(fā)時(shí),我們更多的是在寫(xiě)PHP的邏輯層,但是在寫(xiě)后臺(tái)時(shí)多多少少會(huì)寫(xiě)一寫(xiě)JavaScript的代碼,有時(shí)候我們就會(huì)遇到對(duì)j...
摘要:還規(guī)定了無(wú)窮及其它的相應(yīng)規(guī)范,有興趣可自行查找相關(guān)資料。其它相同數(shù)值相等。類(lèi)型中,引用同一對(duì)象,相等。不同點(diǎn)對(duì)的判斷上各有不同。以為代表的相等和相等以為代表的不相等和相等以為代表的相等和不相等相同類(lèi)型采用嚴(yán)格比較。 相等不相等? 先來(lái)隨便舉幾個(gè)?吧~ 0 == true //? [1] == [1] //? [1] == 1 ...
摘要:可選到該位置前停止讀取數(shù)據(jù),默認(rèn)等于數(shù)組長(zhǎng)度。找出第一個(gè)符合條件的數(shù)組元素,參數(shù)是一個(gè)回調(diào)函數(shù),所有數(shù)組元素依次執(zhí)行該回調(diào)函數(shù),直到找出第一個(gè)返回值為的元素,然后返回該元素。回調(diào)函數(shù)可以接受三個(gè)參數(shù),依次為當(dāng)前的值當(dāng)前的位置和原數(shù)組。 ECMAScript 5.1 中提供的數(shù)組方法 ECMA-262/5.1 規(guī)范 判斷是否是數(shù)組 Array.isArray ( arg ) // fal...
閱讀 644·2021-11-22 15:32
閱讀 2728·2021-11-19 09:40
閱讀 2322·2021-11-17 09:33
閱讀 1280·2021-11-15 11:36
閱讀 1877·2021-10-11 10:59
閱讀 1488·2019-08-29 16:41
閱讀 1792·2019-08-29 13:45
閱讀 2163·2019-08-26 13:36