摘要:規(guī)范對(duì)類(lèi)型的判斷進(jìn)行了細(xì)化,前步可以看成跟的作用一樣,獲取到數(shù)據(jù)的類(lèi)型,但是第步調(diào)用了的方法,如果再看規(guī)范的描述,可以知道這個(gè)其實(shí)是對(duì)象中的屬性,如果這個(gè)屬性返回的是一個(gè)字符串,則采用這個(gè)返回值作為數(shù)據(jù)的類(lèi)型,否則才采用。
所有的悲傷,總會(huì)留下一絲歡樂(lè)的線索,所有的遺憾,總會(huì)留下一處完美的角落,我在冰峰的深海,尋找希望的缺口,卻在驚醒時(shí),瞥見(jiàn)絕美的陽(yáng)光!——幾米
本文為讀 lodash 源碼的第十八篇,后續(xù)文章會(huì)更新到這個(gè)倉(cāng)庫(kù)中,歡迎 star:pocket-lodash
gitbook也會(huì)同步倉(cāng)庫(kù)的更新,gitbook地址:pocket-lodash
作用與用法我們都知道,可以借用 Object 原型上的 toString 方法來(lái)獲取數(shù)據(jù)的類(lèi)型。 baseGetTag 利用的也是這一特性,其返回的結(jié)果如 [object String] 這樣的形式,調(diào)用方式如下:
baseGetTag("string") // [object String]為什么可以用Object.prototype.toString
先看 es5 規(guī)范對(duì) Object.prototyep.toString 的運(yùn)行步驟規(guī)定:
當(dāng)調(diào)用 toString 方法,采用如下步驟:
如果 this 的值是 undefined, 返回 "[object Undefined]".
如果 this 的值是 null, 返回 "[object Null]".
令 O 為以 this 作為參數(shù)調(diào)用 ToObject 的結(jié)果 .
令 class 為 O 的 [[Class]] 內(nèi)部屬性的值 .
返回三個(gè)字符串 "[object ", class, and "]" 連起來(lái)的字符串 .
在第三步的時(shí)候,會(huì)調(diào)用 ToObject 來(lái)轉(zhuǎn)換成對(duì)象,而轉(zhuǎn)換成對(duì)象后,會(huì)有個(gè) [[Class]] 的內(nèi)部屬性,而這個(gè)內(nèi)部屬性的值正是 toString 的關(guān)鍵部分。
接下來(lái)再看規(guī)范對(duì) [[Class]] 的規(guī)定:
本規(guī)范的每種內(nèi)置對(duì)象都定義了 [[Class]] 內(nèi)部屬性的值。宿主對(duì)象的 [[Class]] 內(nèi)部屬性的值可以是除了 "Arguments", "Array", "Boolean", "Date", "Error", "Function", "JSON", "Math", "Number", "Object", "RegExp", "String" 的任何字符串。[[Class]] 內(nèi)部屬性的值用于內(nèi)部區(qū)分對(duì)象的種類(lèi)。注,本規(guī)范中除了通過(guò) Object.prototype.toString ( 見(jiàn) 15.2.4.2) 沒(méi)有提供任何手段使程序訪問(wèn)此值。
由規(guī)范可見(jiàn),要獲取這個(gè) [[Class]] 內(nèi)部屬性的值的唯一手段是通過(guò) Object.prototype.toString 。
源碼分析源碼如下:
const objectProto = Object.prototype const hasOwnProperty = objectProto.hasOwnProperty const toString = objectProto.toString const symToStringTag = typeof Symbol != "undefined" ? Symbol.toStringTag : undefined function baseGetTag(value) { if (value == null) { return value === undefined ? "[object Undefined]" : "[object Null]" } if (!(symToStringTag && symToStringTag in Object(value))) { return toString.call(value) } const isOwn = hasOwnProperty.call(value, symToStringTag) const tag = value[symToStringTag] let unmasked = false try { value[symToStringTag] = undefined unmasked = true } catch (e) {} const result = toString.call(value) if (unmasked) { if (isOwn) { value[symToStringTag] = tag } else { delete value[symToStringTag] } } return result } export default baseGetTagSymbol.toStringTag
在 ES6 中,規(guī)范對(duì) Object.prototype.toString 的步驟進(jìn)行了重新定義,不再使用 [[Class]] 的內(nèi)部屬性進(jìn)行獲取,具體的規(guī)范如下:
在ES6,調(diào)用 Object.prototype.toString 時(shí),會(huì)進(jìn)行如下步驟:
如果 this 是 undefined ,返回 "[object Undefined]" ;
如果 this 是 null , 返回 "[object Null]" ;
令 O 為以 this 作為參數(shù)調(diào)用 ToObject 的結(jié)果;
令 isArray 為 IsArray(O) ;
ReturnIfAbrupt(isArray) (如果 isArray 不是一個(gè)正常值,比如拋出一個(gè)錯(cuò)誤,中斷執(zhí)行);
如果 isArray 為 true , 令 builtinTag 為 "Array" ;
else ,如果 O is an exotic String object , 令 builtinTag 為 "String" ;
else ,如果 O 含有 [[ParameterMap]] internal slot, , 令 builtinTag 為 "Arguments" ;
else ,如果 O 含有 [[Call]] internal method , 令 builtinTag 為 Function ;
else ,如果 O 含有 [[ErrorData]] internal slot , 令 builtinTag 為 Error ;
else ,如果 O 含有 [[BooleanData]] internal slot , 令 builtinTag 為 Boolean ;
else ,如果 O 含有 [[NumberData]] internal slot , 令 builtinTag 為 Number ;
else ,如果 O 含有 [[DateValue]] internal slot , 令 builtinTag 為 Date ;
else ,如果 O 含有 [[RegExpMatcher]] internal slot , 令 builtinTag 為 RegExp ;
else , 令 builtinTag 為 Object ;
令 tag 為 Get(O, @@toStringTag) 的返回值( Get(O, @@toStringTag) 方法,既是在 O 是一個(gè)對(duì)象,并且具有 @@toStringTag 屬性時(shí),返回 O[Symbol.toStringTag] );
ReturnIfAbrupt(tag) ,如果 tag 是正常值,繼續(xù)執(zhí)行下一步;
如果 Type(tag) 不是一個(gè)字符串,let tag be builtinTag ;
返回由三個(gè)字符串 "[object", tag, and "]" 拼接而成的一個(gè)字符串。
規(guī)范對(duì)類(lèi)型的判斷進(jìn)行了細(xì)化,前15步可以看成跟 es5 的作用一樣,獲取到數(shù)據(jù)的類(lèi)型 builtinTag ,但是第16步調(diào)用了 @@toStringTag 的方法,如果再看規(guī)范的描述,可以知道這個(gè)其實(shí)是對(duì)象中的 Symbol.toStringTag 屬性,如果這個(gè)屬性返回的是一個(gè)字符串,則采用這個(gè)返回值 tag 作為數(shù)據(jù)的類(lèi)型,否則才采用 builtinTag 。
處理null和undefinedif (value == null) { return value === undefined ? "[object Undefined]" : "[object Null]" }
這里是處理瀏覽器兼容性,在 es5 之前,并沒(méi)有對(duì) null 和 undefined 進(jìn)行處理,所以返回的都是 [object Object] 。
處理不含Symbol.toStringTag的情況if (!(symToStringTag && symToStringTag in Object(value))) { return toString.call(value) }
如果瀏覽器不支持 Symbol 或者 value 并不存在 Symbol.toStringTag 的方法,則可以直接調(diào)用 toString ,將結(jié)果返回了。
處理Symbol.toStringTag 的情況const isOwn = hasOwnProperty.call(value, symToStringTag) const tag = value[symToStringTag] let unmasked = false try { value[symToStringTag] = undefined unmasked = true } catch (e) {} const result = toString.call(value) if (unmasked) { if (isOwn) { value[symToStringTag] = tag } else { delete value[symToStringTag] } }
為了避免 Symbol.toStringTag 的影響,先將 value 的 Symbol.toStringTag 設(shè)置為 undefined ,這樣可以屏蔽掉原型鏈上的 Symbol.toStringTag 屬性,然后再使用 toString 方法獲取到 value 的屬性描述。
在獲取到屬性描述后,如果 Symbol.toStringTag 為自身的屬性(不為原型鏈上的屬性),則將原來(lái)保存下來(lái)的 tag 重新賦值,否則將 Symbol.toStringTag 屬性移除。
參考es5規(guī)范中文版
Standard ECMA-262
MDN:Symbol.toStringTag
ECMAScript 6 入門(mén)
談?wù)?Object.prototype.toString 。
License署名-非商業(yè)性使用-禁止演繹 4.0 國(guó)際 (CC BY-NC-ND 4.0)
最后,所有文章都會(huì)同步發(fā)送到微信公眾號(hào)上,歡迎關(guān)注,歡迎提意見(jiàn):
作者:對(duì)角另一面
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/94004.html
摘要:實(shí)例中構(gòu)造函數(shù)的獲取每個(gè)實(shí)例中都包含一個(gè)的屬性,這個(gè)屬性指向的是實(shí)例的構(gòu)造函數(shù),在獲取到這個(gè)構(gòu)造函數(shù)后,就可以調(diào)用它的方法,然后就可以比較了。 焦慮和恐懼的區(qū)別是,恐懼是對(duì)世界上的存在的恐懼,而焦慮是在我面前的焦慮?!_特《存在與虛無(wú)》 本文為讀 lodash 源碼的第十九篇,后續(xù)文章會(huì)更新到這個(gè)倉(cāng)庫(kù)中,歡迎 star:pocket-lodash gitbook也會(huì)同步倉(cāng)庫(kù)的更新,...
摘要:接口設(shè)計(jì)同樣實(shí)現(xiàn)了跟一致的數(shù)據(jù)管理接口,如下依賴(lài)源碼分析之緩存源碼分析之緩存源碼分析是否使用這個(gè)函數(shù)用來(lái)判斷是否使用緩存。返回表示使用緩存,返回則使用或者緩存。獲取對(duì)應(yīng)緩存方式的實(shí)例這個(gè)函數(shù)根據(jù)來(lái)獲取儲(chǔ)存了該的緩存實(shí)例。 每個(gè)人心里都有一團(tuán)火,路過(guò)的人只看到煙。——《至愛(ài)梵高·星空之謎》 本文為讀 lodash 源碼的第八篇,后續(xù)文章會(huì)更新到這個(gè)倉(cāng)庫(kù)中,歡迎 star:pocket-...
摘要:接口設(shè)計(jì)同樣實(shí)現(xiàn)了跟一致的數(shù)據(jù)管理接口,如下依賴(lài)源碼分析之緩存源碼分析之緩存源碼分析是否使用這個(gè)函數(shù)用來(lái)判斷是否使用緩存。返回表示使用緩存,返回則使用或者緩存。獲取對(duì)應(yīng)緩存方式的實(shí)例這個(gè)函數(shù)根據(jù)來(lái)獲取儲(chǔ)存了該的緩存實(shí)例。 每個(gè)人心里都有一團(tuán)火,路過(guò)的人只看到煙?!吨翋?ài)梵高·星空之謎》 本文為讀 lodash 源碼的第八篇,后續(xù)文章會(huì)更新到這個(gè)倉(cāng)庫(kù)中,歡迎 star:pocket-...
摘要:卡爾維諾煙云本文為讀源碼的第二十一篇,后續(xù)文章會(huì)更新到這個(gè)倉(cāng)庫(kù)中,歡迎也會(huì)同步倉(cāng)庫(kù)的更新,地址依賴(lài)源碼分析之?dāng)?shù)據(jù)類(lèi)型獲取的兼容性源碼分析之源碼分析用來(lái)判斷某個(gè)值是否為類(lèi)對(duì)象。如果某個(gè)值為類(lèi)對(duì)象使用判斷,并且調(diào)用返回的值為時(shí),則為類(lèi)對(duì)象。 有人命中注定要過(guò)平庸的生活,默默無(wú)聞,因?yàn)樗麄兘?jīng)歷了痛苦或不幸;有人卻故意這樣做,那是因?yàn)樗麄兊玫降男腋3^(guò)了他們的承受能力。——卡爾維諾《煙云》 ...
摘要:在之前的文章中已經(jīng)介紹過(guò),檢測(cè)的是對(duì)應(yīng)的數(shù)組在二維數(shù)組中的索引,其行為跟一致,不存在于二維數(shù)組中時(shí),返回,否則返回索引值。最后將緩存數(shù)量減少。 昨日我沿著河岸/漫步到/蘆葦彎腰喝水的地方順便請(qǐng)煙囪/在天空為我寫(xiě)一封長(zhǎng)長(zhǎng)的信 潦是潦草了些/而我的心意/則明亮亦如你窗前的燭光/稍有曖昧之處/勢(shì)所難免/因?yàn)轱L(fēng)的緣故 ——洛夫《因?yàn)轱L(fēng)的緣故》 本文為讀 lodash 源碼的第七篇,后續(xù)文章會(huì)...
閱讀 1395·2021-11-04 16:11
閱讀 3059·2021-10-12 10:11
閱讀 2991·2021-09-29 09:47
閱讀 1627·2021-09-22 15:40
閱讀 1025·2019-08-29 15:43
閱讀 2814·2019-08-29 13:50
閱讀 1591·2019-08-29 13:28
閱讀 2698·2019-08-29 12:54