成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

lodash源碼分析之獲取數(shù)據(jù)類(lèi)型

huangjinnan / 3378人閱讀

摘要:規(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 baseGetTag
Symbol.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)行如下步驟:

如果 thisundefined ,返回 "[object Undefined]" ;

如果 thisnull , 返回 "[object Null]" ;

O 為以 this 作為參數(shù)調(diào)用 ToObject 的結(jié)果;

isArrayIsArray(O) ;

ReturnIfAbrupt(isArray) (如果 isArray 不是一個(gè)正常值,比如拋出一個(gè)錯(cuò)誤,中斷執(zhí)行);

如果 isArraytrue , 令 builtinTag"Array" ;

else ,如果 O is an exotic String object , 令 builtinTag"String"

else ,如果 O 含有 [[ParameterMap]] internal slot, , 令 builtinTag"Arguments" ;

else ,如果 O 含有 [[Call]] internal method , 令 builtinTagFunction ;

else ,如果 O 含有 [[ErrorData]] internal slot , 令 builtinTagError

else ,如果 O 含有 [[BooleanData]] internal slot , 令 builtinTagBoolean

else ,如果 O 含有 [[NumberData]] internal slot , 令 builtinTagNumber ;

else ,如果 O 含有 [[DateValue]] internal slot , 令 builtinTagDate ;

else ,如果 O 含有 [[RegExpMatcher]] internal slot , 令 builtinTagRegExp ;

else , 令 builtinTagObject ;

tagGet(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和undefined
if (value == null) {
  return value === undefined ? "[object Undefined]" : "[object Null]"
}

這里是處理瀏覽器兼容性,在 es5 之前,并沒(méi)有對(duì) nullundefined 進(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 的影響,先將 valueSymbol.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

相關(guān)文章

  • lodash源碼分析數(shù)據(jù)類(lèi)型獲取的兼容性

    摘要:實(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ù)的更新,...

    avwu 評(píng)論0 收藏0
  • lodash源碼分析緩存方式的選擇

    摘要:接口設(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-...

    HitenDev 評(píng)論0 收藏0
  • lodash源碼分析緩存方式的選擇

    摘要:接口設(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-...

    AdolphLWQ 評(píng)論0 收藏0
  • lodash源碼分析isArguments

    摘要:卡爾維諾煙云本文為讀源碼的第二十一篇,后續(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ò)了他們的承受能力。——卡爾維諾《煙云》 ...

    _Dreams 評(píng)論0 收藏0
  • lodash源碼分析List緩存

    摘要:在之前的文章中已經(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ì)...

    leon 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<