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