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