lodash原始碼分析之資料型別獲取的相容性

对角另一面發表於2018-09-24

焦慮和恐懼的區別是,恐懼是對世界上的存在的恐懼,而焦慮是在"我"面前的焦慮。

——薩特《存在與虛無》

本文為讀 lodash 原始碼的第十九篇,後續文章會更新到這個倉庫中,歡迎 star:pocket-lodash

gitbook也會同步倉庫的更新,gitbook地址:pocket-lodash

前言

在前文《lodash原始碼分析之獲取資料型別》已經解釋了獲取資料型別的方法,但是在有些環境下,一些 es6 新增的物件獲取到的型別都為 [object Object] ,這樣就沒辦法做細緻的區分。例如在 IE11 中,通過 Object.prototype.toString 獲取到的 DataView 物件型別為 [object Object]。 因此在 getTag 中,lodash 針對這些物件做了一些相容性的事情。

依賴

import baseGetTag from './baseGetTag.js'
複製程式碼

lodash原始碼分析之獲取資料型別

原始碼分析

const dataViewTag = '[object DataView]'
const mapTag = '[object Map]'
const objectTag = '[object Object]'
const promiseTag = '[object Promise]'
const setTag = '[object Set]'
const weakMapTag = '[object WeakMap]'

/** Used to detect maps, sets, and weakmaps. */
const dataViewCtorString = `${DataView}`
const mapCtorString = `${Map}`
const promiseCtorString = `${Promise}`
const setCtorString = `${Set}`
const weakMapCtorString = `${WeakMap}`

let getTag = baseGetTag

// Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6.
if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||
    (getTag(new Map) != mapTag) ||
    (getTag(Promise.resolve()) != promiseTag) ||
    (getTag(new Set) != setTag) ||
    (getTag(new WeakMap) != weakMapTag)) {
  getTag = (value) => {
    const result = baseGetTag(value)
    const Ctor = result == objectTag ? value.constructor : undefined
    const ctorString = Ctor ? `${Ctor}` : ''

    if (ctorString) {
      switch (ctorString) {
        case dataViewCtorString: return dataViewTag
        case mapCtorString: return mapTag
        case promiseCtorString: return promiseTag
        case setCtorString: return setTag
        case weakMapCtorString: return weakMapTag
      }
    }
    return result
  }
}
複製程式碼

getTag 的原始碼很簡單,處理的是 DataViewMapSetPromiseWeakMap 等物件,下面就關鍵的幾點說明一下。

函式的toString方法

const dataViewCtorString = `${DataView}`
const mapCtorString = `${Map}`
const promiseCtorString = `${Promise}`
const setCtorString = `${Set}`
const weakMapCtorString = `${WeakMap}`
複製程式碼

我們都知道,DataView 這些其實都是建構函式,函式有 toString 的方法,呼叫後返回的是 function DataView() { [native code] } 這樣的格式,因為其例項呼叫 Object.prototype.toString 在某些環境下返回的是 [object Object],而建構函式的 toString 返回的字串中,包含了建構函式名,可以通過這點來區分。

例項中建構函式的獲取

 const Ctor = result == objectTag ? value.constructor : undefined
 const ctorString = Ctor ? `${Ctor}` : ''
複製程式碼

每個例項中都包含一個 constructor 的屬性,這個屬性指向的是例項的建構函式,在獲取到這個建構函式後,就可以呼叫它的 toString 方法,然後就可以比較了。

Promise.resolve

getTag(Promise.resolve()) != promiseTag
複製程式碼

在條件判斷時,使用了 Promise.resolve() ,這樣使用的目的是獲取到 promise 物件,因為 Promise 是一個函式函式,如果直接呼叫 Object.prototype.toString,返回的是 [object Function]

License

署名-非商業性使用-禁止演繹 4.0 國際 (CC BY-NC-ND 4.0)

最後,所有文章都會同步傳送到微信公眾號上,歡迎關注,歡迎提意見:

lodash原始碼分析之資料型別獲取的相容性

作者:對角另一面

相關文章