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