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

資訊專欄INFORMATION COLUMN

Lodash 是如何做類型檢測(cè)的

keke / 1758人閱讀

摘要:與之前的類似,利用構(gòu)造函數(shù)創(chuàng)建的字符串是一個(gè)所以檢測(cè)字符串,除了基本字符串以外還要注意字符串對(duì)象。也就是說(shuō)該對(duì)象由構(gòu)造函數(shù)創(chuàng)建,或者為。

原文:https://fatge.github.io/2019/...
歡迎Star:https://github.com/FatGe/FatG...

JS 的基本數(shù)據(jù)類型有 NumberString,Boolean,Symbol,Null,Undefined,六種數(shù)據(jù)類型。一種引用類型 object。

基本數(shù)據(jù)類型 Number

數(shù)值,根據(jù) ECMAScript 標(biāo)準(zhǔn),JavaScript 中只有一種數(shù)字類型:基于 IEEE 754 標(biāo)準(zhǔn)的雙精度 64 位二進(jìn)制格式的值(-(263 -1) 到 263 -1)。它并沒(méi)有為整數(shù)給出一種特定的類型。

除了能夠表示浮點(diǎn)數(shù)外,還有一些帶符號(hào)的值:+Infinity,-InfinityNaN (非數(shù)值,Not-a-Number)。

對(duì)應(yīng) lodash 中的檢測(cè)函數(shù)有

isNumber 檢查 value 是否是原始 Number 數(shù)值型 或者 對(duì)象;

isInteger 檢查 value 是否為一個(gè)整數(shù);

isNaN 檢測(cè) value 是否為 NaN;

isFinite 檢測(cè) value 是否是原始有限數(shù)值。

isNumber
function isNumber(value) {
  return typeof value == "number" ||
    (isObjectLike(value) && getTag(value) == "[object Number]")
}

typeof 操作符可以返回一個(gè)字符串,表示未經(jīng)計(jì)算的操作數(shù)的類型。對(duì)于 Number、String、Boolean、Undefined、String 可以很明確的得到它的類型。

那么 lodash 為什么還要添加 (isObjectLike(value) && getTag(value) == "[object Number]")?

原因在于,JS 中也允許我們以如下形式創(chuàng)建一個(gè)數(shù)值

const value = new Number(1)
console.log(value) // log 1
console.log(typeof value) // log "object"

這時(shí),單單只是使用 typeof 操作符就沒(méi)法判斷 value 的類型是否為數(shù)值。所以要結(jié)合以下兩個(gè)函數(shù)來(lái)判斷,value 是否為 object 然后再通過(guò)過(guò) toString() 來(lái)獲取每個(gè)對(duì)象的類型。

function getTag(value) {
  if (value == null) {
    return value === undefined ? "[object Undefined]" : "[object Null]"
  }
  return Object.prototype.toString.call(value)  
}

function isObjectLike(value) {
  return typeof value == "object" && value !== null
}
Object.prototype.toString.call 每個(gè)對(duì)象都有一個(gè)toString()方法,當(dāng)該對(duì)象被表示為一個(gè)文本值時(shí),或者一個(gè)對(duì)象以預(yù)期的字符串方式引用時(shí)自動(dòng)調(diào)用。
isInteger
function isInteger(value) {
    return 
        typeof value == "number" 
        && value == toInteger(value);
}

檢查 value 是否為一個(gè)整數(shù),判斷是否 value 的類型是否為數(shù)值,并且是否與 Int 型相同。其取整過(guò)程如下

function toInteger(value) {
    var result = toFinite(value),
        remainder = result % 1;

    return result === result ? 
        (remainder ? result - remainder : result) : 0;
}
isNaN

檢查 value 是否是 NaN。

function isNaN(value) {
    return isNumber(value) && value != +value;
}

與 ES 2015 的 isNaN 不同的是,對(duì)于 undefined,{},原生的結(jié)果是 true,而 lodashfalse。這是因?yàn)槿绻?b>isNaN函數(shù)的參數(shù)不是Number類型, isNaN函數(shù)會(huì)首先嘗試將這個(gè)參數(shù)轉(zhuǎn)換為數(shù)值,然后才會(huì)對(duì)轉(zhuǎn)換后的結(jié)果是否是NaN進(jìn)行判斷。

// js native isNaN
var isNaN = function(value) {
    var n = Number(value);
    return n !== n;
};

但是無(wú)論是 ES 2015 還是 lodash,它們本質(zhì)上都是利用 x != x 來(lái)判斷 NaN。

isFinite

檢查 value 是否是原始有限數(shù)值。

function isFinite(value) {
    return typeof value == "number" 
        && nativeIsFinite(value);
}

利用原生的 isFinite 結(jié)合 typeof 判斷數(shù)字是否為有限值。

String

String 類型用于表示由零或多個(gè)16 位Unicode 字符組成的字符序列,即字符串。用于保存可以以文本形式表示的數(shù)據(jù)非常有用。

值得注意的是,不單單要注意基本字符串,還需要注意字符串對(duì)象,字符串字面量 (通過(guò)單引號(hào)或雙引號(hào)定義) 和 直接調(diào)用 String 方法(沒(méi)有通過(guò) new 生成字符串對(duì)象實(shí)例)的字符串都是基本字符串。

JavaScript會(huì)自動(dòng)將基本字符串轉(zhuǎn)換為字符串對(duì)象,只有將基本字符串轉(zhuǎn)化為字符串對(duì)象之后才可以使用字符串對(duì)象的方法。

與之前的 number 類似,利用構(gòu)造函數(shù) String 創(chuàng)建的字符串是一個(gè) object

const s_prim = "foo";
const s_obj = new String(s_prim);

console.log(typeof s_prim); // Logs "string"
console.log(typeof s_obj);  // Logs "object"

所以檢測(cè)字符串,除了基本字符串以外還要注意字符串對(duì)象。

function isString(value) {
  const type = typeof value
  return 
    type == "string" || 
        (type == "object" 
             && value != null 
             && !Array.isArray(value) 
             && getTag(value) == "[object String]")
}

可以利用 typeof 檢測(cè)基本字符串,對(duì)于模板字符串采用了之前介紹的方案 getTag 來(lái)獲取 value 的類型。

Boolean

Boolean 類型是ECMAScript 中使用得最多的一種類型,該類型只有兩個(gè)字面值:truefalse。同樣也需要區(qū)分基本的 Boolean 類型以及 Boolean 對(duì)象。

function isBoolean(value) {
  return 
    value === true || value === false ||
    (isObjectLike(value) 
     && getTag(value) == "[object Boolean]")
}

大部分在之前都已經(jīng)涉及到了,這里出現(xiàn)了 isObjectLike,那么它是做什么的。

function isObjectLike(value) {
  return typeof value == "object" && value !== null
}

原來(lái)只是檢測(cè)是否是一個(gè)非 null 的對(duì)象。

Symbol

ES6 引入了一種新的原始數(shù)據(jù)類型Symbol,表示獨(dú)一無(wú)二的值。Symbol 值通過(guò)Symbol函數(shù)生成。

function isSymbol(value) {
  const type = typeof value
  return type == "symbol" || 
      (isObjectLike(value) && 
       getTag(value) == "[object Symbol]")
}

會(huì)發(fā)現(xiàn) (isObjectLike(value) && getTag(value) == "[object Symbol]"),也對(duì) Symbol 對(duì)象進(jìn)行檢測(cè),但是如果直接 new Symbol 會(huì) log 出 TypeError。

那么 lodash 為什么要對(duì)其進(jìn)行檢測(cè),原來(lái)是創(chuàng)建一個(gè)顯式包裝器對(duì)象從 ECMAScript 6 開始不再被支持,現(xiàn)在可以利用如下代碼來(lái)模擬,雖然沒(méi)什么用。

const sym = Symbol("foo");
typeof sym;     // "symbol"
const symObj = Object(sym);
typeof symObj;  // "object"
Undefined

Undefined 類型只有一個(gè)值,即特殊的 undefined。在使用 letvar 聲明變量但未對(duì)其加以初始化時(shí),這個(gè)變量的值就是 undefined。

function isUndefined(value) {
    return value === undefined;
}
Null

Null 類型是只有一個(gè)值的數(shù)據(jù)類型,這個(gè)特殊的值是 null 。與 undefined 不同的是,它是一個(gè)字面量,而 undefined 是全局對(duì)象的一個(gè)屬性。

從邏輯角度來(lái)看,null 值表示一個(gè)空對(duì)象指針,null 是表示缺少的標(biāo)識(shí),指示變量未指向任何對(duì)象。而這也正是使用typeof 操作符檢測(cè)null 值時(shí)會(huì)返回"object"的原因。

對(duì)其的判斷也非常的簡(jiǎn)單,只需要

function isNull(value) {
  return value === null
}

當(dāng)然你也可以使用

console.log(Object.prototype.toString.call(null))
// [object Null]

以上是基本數(shù)據(jù)類型的判斷,總結(jié)一下,主要是利用 typeOf 以及 Object.prototype.toString ,還有一些特殊值的特性。下面開始分析引用類型 Object

引用類型

引用類型的值(對(duì)象)是引用類型的一個(gè)實(shí)例。在ECMAScript 中,引用類型是一種數(shù)據(jù)結(jié)構(gòu),用于將數(shù)據(jù)和功能組織在一起。具體的有 ObjectArray、Date、Error、RegExp、Function,還有ES2015 引入 Set、Map、WeakSetWeakMap。

Object

ECMAScript 中的對(duì)象其實(shí)就是一組數(shù)據(jù)和功能的集合。它有一個(gè)很重要的用途,就是在 JavaScript 中的所有對(duì)象都來(lái)自 Object;所有對(duì)象從Object.prototype繼承方法和屬性,盡管它們可能被覆蓋。即在ECMAScript 中,Object 類型是所有它的實(shí)例的基礎(chǔ)。

所以 Lodash 去判斷 value 是否為 Object 時(shí),只使用了 typeOf 操作即可。

function isObject(value) {
  const type = typeof value
  return value != null && 
      (type == "object" || type == "function")
}
Function

Function 構(gòu)造函數(shù) 創(chuàng)建一個(gè)新的Function對(duì)象。 在 JavaScript 中, 每個(gè)函數(shù)實(shí)際上都是一個(gè)Function對(duì)象。

function isFunction(value) {
  if (!isObject(value)) {
    return false
  }

  const tag = getTag(value)
  return tag == "[object Function]" || 
          tag == "[object AsyncFunction]" ||
        tag == "[object GeneratorFunction]" || 
          tag == "[object Proxy]"
}

有個(gè)問(wèn)題,typeOf 可以檢測(cè) Function對(duì)象的類型為 Function, 那為什么還需要 Object.prototype.toString 呢?

// in Safari 9 which returns "object" for typed arrays and other constructors.
Array

Array 在 ECMAScript 中代表數(shù)組,它的每一項(xiàng)可以保存任何類型的數(shù)據(jù)。

對(duì)它的常規(guī)檢測(cè)就是 Array.isArray,Lodash 也是使用這個(gè) API,如果需要 Polyfill 方案的話,可以使用

// plan 1
Object.prototype.toString.call(value) === "[object Array]"
// plan 2
value.constructor === Array

之前還有 value instanceof Array 會(huì)什么問(wèn)題么?

在存在不同全局變量的環(huán)境,通過(guò)語(yǔ)義 instanceof 檢測(cè)數(shù)組的時(shí)候,value instanceof Array只有當(dāng) value 是由該頁(yè)面的原始 Array 構(gòu)造函數(shù)創(chuàng)建的數(shù)組時(shí)才能正常工作。

具體請(qǐng)見,http://web.mit.edu/jwalden/ww...。

Date

ECMAScript 中的 Date 類型是在早期Java 中的java.util.Date 類基礎(chǔ)上構(gòu)建的。

const nodeIsDate = nodeTypes && nodeTypes.isDate

const isDate = nodeIsDate
  ? (value) => nodeIsDate(value)
  : (value) => isObjectLike(value) && getTag(value) == "[object Date]"

Lodash 分為兩個(gè)環(huán)境來(lái)處理這個(gè)問(wèn)題,如果是 Node 就利用 util.types.isDate(value) 來(lái)檢測(cè),如果是在游覽器,就還是通過(guò) Object.prototype.toString 來(lái)判斷。

Set

ES2015 提供了新的數(shù)據(jù)結(jié)構(gòu) Set。它類似于數(shù)組,但是成員的值都是唯一的,沒(méi)有重復(fù)的值。

const isSet = nodeIsSet
  ? (value) => nodeIsSet(value)
  : (value) => isObjectLike(value) && getTag(value) == "[object Set]"

同樣的還有 Map

const isMap = nodeIsMap
  ? (value) => nodeIsMap(value)
  : (value) => isObjectLike(value) && getTag(value) == "[object Map]"
WeakSet

WeakSet 結(jié)構(gòu)與 Set 類似,也是不重復(fù)的值的集合。但是,它與 Set 有兩個(gè)區(qū)別。

function isWeakSet(value) {
  return isObjectLike(value) && getTag(value) == "[object WeakSet]"
}

也是利用 Object.prototype.toString ,同樣還有 WeakMap

function isWeakMap(value) {
  return isObjectLike(value) && getTag(value) == "[object WeakMap]"
}
Error

當(dāng)運(yùn)行時(shí)錯(cuò)誤產(chǎn)生時(shí),Error的實(shí)例對(duì)象會(huì)被拋出。

function isError(value) {
  if (!isObjectLike(value)) {
    return false
  }
    
  const tag = getTag(value)
  return tag == "[object Error]" || 
      tag == "[object DOMException]" ||
    (typeof value.message == "string" && typeof value.name == "string" && !isPlainObject(value))
}

有之前一致的 Object.prototype.toString 依然可以用來(lái)判斷對(duì)象是否是一個(gè) Error,除此之外,如果對(duì)象滿足以下條件,也可以被視為一個(gè) Error

具備 message、name 屬性,且值為 string;

是普通對(duì)象。 也就是說(shuō)該對(duì)象由 Object 構(gòu)造函數(shù)創(chuàng)建,或者 [[Prototype]]null 。

那么如何檢測(cè)普通對(duì)象呢?

function isPlainObject(value) {
  if (!isObjectLike(value) || getTag(value) != "[object Object]") {
    return false
  }
  if (Object.getPrototypeOf(value) === null) {
    return true
  }
  let proto = value
  while (Object.getPrototypeOf(proto) !== null) {
    proto = Object.getPrototypeOf(proto)
  }
  return Object.getPrototypeOf(value) === proto
}

主要是利用 Object.getPrototypeOf() 方法返回指定對(duì)象的原型(內(nèi)部[[Prototype]]屬性的值),同時(shí)和 value 本身的 [[Prototype]] 做判斷。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/106178.html

相關(guān)文章

  • JavaScript 深拷貝

    摘要:深拷貝是一件看起來(lái)很簡(jiǎn)單的事情,但其實(shí)一點(diǎn)兒也不簡(jiǎn)單。我們也可以利用這個(gè)實(shí)現(xiàn)對(duì)象的深拷貝。而是利用之前已經(jīng)拷貝好的值。深拷貝的詳細(xì)的源碼可以在這里查看。大功告成我們雖然的確解決了深拷貝的大部分問(wèn)題。 js深拷貝是一件看起來(lái)很簡(jiǎn)單的事情,但其實(shí)一點(diǎn)兒也不簡(jiǎn)單。對(duì)于循環(huán)引用的問(wèn)題還有一些內(nèi)置數(shù)據(jù)類型的拷貝,如Map, Set, RegExp, Date, ArrayBuffer 和其他內(nèi)置...

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

    摘要:在之前的文章中已經(jīng)介紹過(guò),檢測(cè)的是對(duì)應(yīng)的數(shù)組在二維數(shù)組中的索引,其行為跟一致,不存在于二維數(shù)組中時(shí),返回,否則返回索引值。最后將緩存數(shù)量減少。 昨日我沿著河岸/漫步到/蘆葦彎腰喝水的地方順便請(qǐng)煙囪/在天空為我寫一封長(zhǎng)長(zhǎng)的信 潦是潦草了些/而我的心意/則明亮亦如你窗前的燭光/稍有曖昧之處/勢(shì)所難免/因?yàn)轱L(fēng)的緣故 ——洛夫《因?yàn)轱L(fēng)的緣故》 本文為讀 lodash 源碼的第七篇,后續(xù)文章會(huì)...

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

    摘要:在之前的文章中已經(jīng)介紹過(guò),檢測(cè)的是對(duì)應(yīng)的數(shù)組在二維數(shù)組中的索引,其行為跟一致,不存在于二維數(shù)組中時(shí),返回,否則返回索引值。最后將緩存數(shù)量減少。 昨日我沿著河岸/漫步到/蘆葦彎腰喝水的地方順便請(qǐng)煙囪/在天空為我寫一封長(zhǎng)長(zhǎng)的信 潦是潦草了些/而我的心意/則明亮亦如你窗前的燭光/稍有曖昧之處/勢(shì)所難免/因?yàn)轱L(fēng)的緣故 ——洛夫《因?yàn)轱L(fēng)的緣故》 本文為讀 lodash 源碼的第七篇,后續(xù)文章會(huì)...

    SunZhaopeng 評(píng)論0 收藏0
  • 「讀懂源碼系列3」lodash 如何實(shí)現(xiàn)深拷貝(上)

    摘要:上對(duì)位運(yùn)算的解釋是它經(jīng)常被用來(lái)創(chuàng)建處理以及讀取標(biāo)志位序列一種類似二進(jìn)制的變量。位運(yùn)算,常用于處理同時(shí)存在多個(gè)布爾選項(xiàng)的情形。掩碼中的每個(gè)選項(xiàng)的值都是的冪,位運(yùn)算是位的。位運(yùn)算,說(shuō)白了就是直接對(duì)某個(gè)數(shù)據(jù)在內(nèi)存中的二進(jìn)制位,進(jìn)行運(yùn)算操作。 showImg(https://segmentfault.com/img/bVbrC56?w=2208&h=1242); 前言 上一篇文章 「前端面試題...

    flyer_dev 評(píng)論0 收藏0
  • 「讀懂源碼系列4」lodash 如何實(shí)現(xiàn)深拷貝(下)

    摘要:用于檢測(cè)自己是否在自己的原型鏈上如果是函數(shù),則取出該函數(shù)的原型對(duì)象否則,取出對(duì)象的原型對(duì)象其中,的判斷,是為了確定的類型是對(duì)象或數(shù)組。相當(dāng)于,而的構(gòu)造函數(shù)是一個(gè)函數(shù)對(duì)象。 showImg(https://segmentfault.com/img/bVbq2N1?w=640&h=437); 前言 接著上一篇文章 lodash 是如何實(shí)現(xiàn)深拷貝的(上),今天會(huì)繼續(xù)解讀 _.cloneDee...

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

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

0條評(píng)論

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