欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

關(guān)于JS數(shù)據(jù)類型檢測(cè)的多種方式總結(jié)

 更新時(shí)間:2021年09月03日 16:12:02   作者:鄭魚咚  
Javascript中檢查數(shù)據(jù)類型一直是老生常談的問題,類型判斷在web開發(fā)中也有著非常廣泛的應(yīng)用,所以下面這篇文章主要給大家介紹了關(guān)于JS數(shù)據(jù)類型檢測(cè)的那些事,需要的朋友可以參考下

背景

總所周知,js是一門動(dòng)態(tài)的弱類型腳本語言,其采用動(dòng)態(tài)的類型系統(tǒng)以及基于原型的繼承方式。

缺乏類型的靜態(tài)約束,這意味著數(shù)據(jù)類型導(dǎo)致的程序錯(cuò)誤并不能在編譯階段及時(shí)發(fā)現(xiàn),要想寫出健壯的代碼,就必須在運(yùn)行時(shí)各種的check&兼容,所以能夠熟練準(zhǔn)確的檢測(cè)數(shù)據(jù)類型成為掌握這門語言最重要的基礎(chǔ)之一。

判斷數(shù)據(jù)類型的手段有哪些?

總的來說大致有以下幾種:typeof、instanceof、Object.prototype.toString、constructor、鴨式類型、及針對(duì)特定類型的檢測(cè)方法Array.isArray(),Number.isNaN(),雖然方法很多,但他們的使用場(chǎng)景有所不同。

1. 用typeof判斷基礎(chǔ)數(shù)據(jù)類型:

返回值有undefined、string、number、boolean、object、function、symbol七種。

可以看出,typeof作為官方提供的類型檢測(cè)操作符,在檢測(cè)undefined、string、boolean、symbol這些基本數(shù)據(jù)類型及function方面是十分靠譜的。表現(xiàn)拉垮的地方主要在于

1) 不能對(duì)具體對(duì)象類型(Array、Date、regExp)進(jìn)行區(qū)分。
2) typeof null === 'object' // 竟然是true。。。。

缺陷 2)可以避免,在判斷對(duì)象引用類型時(shí)多判斷一句即可,typeof x === 'object' &&  x !== null。但是不能區(qū)分對(duì)象的具體類型,確實(shí)是個(gè)很大痛點(diǎn)。

2. 用instanceof判斷對(duì)象數(shù)據(jù)類型

此運(yùn)算符用于檢測(cè)某個(gè)構(gòu)造函數(shù)的prototype是否出現(xiàn)在目標(biāo)對(duì)象的原型鏈上。

這是一種預(yù)測(cè)的檢測(cè)方式,并不會(huì)像typeof一樣直接將數(shù)據(jù)類型以字符串的方式進(jìn)行返回,而是你需要預(yù)判對(duì)象類型的構(gòu)造函數(shù),最終返回一個(gè)boolean值。

檢測(cè)規(guī)則其實(shí)從命名就可以看出,判斷實(shí)例是否是由某個(gè)構(gòu)造函數(shù)所創(chuàng)建的,那么知道了原理,現(xiàn)在動(dòng)手實(shí)現(xiàn)一個(gè)屬于自己的instanceof。

function myInstanceof(target,constructor){
  const baseType = ['string', 'number','boolean','undefined','symbol']
    if(baseType.includes(typeof(target))) { return false }
    //原型鏈其實(shí)就是個(gè)對(duì)象組成的鏈表,遍歷這個(gè)鏈表,
  let prototype = Object.getPrototypeOf(target);
    while(prototype){
        //一旦鏈上有對(duì)象有符合,就返回true
      if(prototype === constructor.prototype){
        return true
      }else{
        prototype = Object.getPrototypeOf(prototype)
      }
    }
    return false
}
console.log(myInstanceof([],Array))

在js里,可以從廣義上認(rèn)為萬物源于對(duì)象,因?yàn)閷?shí)例雖然是通過構(gòu)造函數(shù)創(chuàng)建的,但是構(gòu)造函數(shù)本身只是沒有感情的生產(chǎn)機(jī)器,實(shí)例的靈魂和性格(公共屬性和方法)都是共享自構(gòu)造函數(shù)的prototype屬性指向的那個(gè)原型對(duì)象,而且原型對(duì)象都是純對(duì)象,純對(duì)象又是由Object構(gòu)造函數(shù)創(chuàng)建的,那么就會(huì)造成下邊這種后果。

對(duì)于數(shù)組,遍歷原型鏈上的對(duì)象,Array.prototype Object.prototype都會(huì)出現(xiàn)。

并且,對(duì)字面量方式創(chuàng)建的基本數(shù)據(jù)類型無法進(jìn)行判斷。比如

如何彌補(bǔ)上邊的缺陷呢,答案是可以在上邊特殊的場(chǎng)景中采用下邊的constructor代替instanceof。

3. 用contructor屬性

首先先明確。constructor是原型上的屬性,實(shí)例繼承自原型,所以實(shí)例上也能直接訪問此屬性。
首先看下contructor的通用性表現(xiàn)

意外的表現(xiàn)不錯(cuò),除了null、undefined,有contructor屬性的基礎(chǔ)(包裝)類型或者對(duì)象類型都能準(zhǔn)確判斷。

能準(zhǔn)確區(qū)分Array|Object 因?yàn)樗鼪]有instanceof那樣會(huì)遍歷整條原型鏈,只是在實(shí)例身上進(jìn)行判斷。但也有個(gè)致命的缺陷,實(shí)例上的這一屬性太容易被修改了,一旦修改,這個(gè)方法就沒有意義了。

4. toString方法

首先,js的對(duì)象類型或者基礎(chǔ)類型的包裝對(duì)象都有一個(gè)toString方法。繼承自O(shè)bject.prototype.toString(),調(diào)用會(huì)返回對(duì)應(yīng)類型的字符串標(biāo)記"[object Type]"。

這個(gè)方法有種亂拳打死老師傅,無心插柳柳成蔭的感覺,本來的作用只是得到一個(gè)表示該對(duì)象的字符串,現(xiàn)在用在js類型檢測(cè)上,表現(xiàn)簡(jiǎn)直不要太好,針對(duì)基礎(chǔ)類型及對(duì)象類型表現(xiàn)都非常不錯(cuò),如果非要說個(gè)缺點(diǎn),只能說返回的字符串有點(diǎn)復(fù)雜,使用不太方便,現(xiàn)在讓我們動(dòng)手簡(jiǎn)化一下。

先寫一個(gè)簡(jiǎn)版

function isType(type,value){
    return Object.prototype.toString.call(value) === `[object ${type}]`
}
console.log(isType('Array',[]))
console.log(isType('Number',1))

這樣使用也不太方便,‘Array' ‘Number'這樣的類型參數(shù),很容易拼寫錯(cuò)誤,所以希望方法可以預(yù)設(shè)參數(shù),并且希望構(gòu)造一個(gè)函數(shù)工廠,調(diào)用返回類似于isArray這樣的函數(shù)。在IDE中函數(shù)名相比字符串會(huì)擁有更好的代碼提示,不容易拼寫錯(cuò)誤。

function isType(type){
    return function(value){
        return Object.prototype.toString.call(value) === `[object ${type}]`
    }
}

const isArray = isType('Array')
const isNumber = isType('Number')
console.log(isArray([]),isNumber(1))

這里運(yùn)用了高階函數(shù)的思想,保留參數(shù)+返回一個(gè)新的函數(shù),那么可以想到j(luò)s里bind除了可以綁定this,也有保留參數(shù)+返回新函數(shù)的功能,用在這里也很合適。

function isType(type,value){
    return Object.prototype.toString.call(value) === `[object ${type}]`
}

const isArray = isType.bind(null,'Array')
const isNumber = isType.bind(null,'Number')
console.log(isArray([]),isNumber(1))

更進(jìn)一步,用參數(shù)柯里化的思想改造一波

function isType(type,value){
    return Object.prototype.toString.call(value) === `[object ${type}]`
}
function curring (fn,...args1){
    let len = fn.length;
    return function(...args2){
        const args = args1.concat(args2);
        if(args.length < len){
            return curring(fn,...args)
        }else{
            return fn(...args)
        }
    }
}
const isArray = curring(isType,'Array')
const isNumber = curring(isType,'Number')
console.log(isArray([]),isNumber(1))

最后,豐富一下支持的類型,大功告成。

const types = [
    'Null',
    'Undefined',
    'String',
    'Number',
    'Boolean',
    'Object',
    'Array',
    'Date',
    'Function',
    'RegExp',
    'Symbol',
    'Math',
]
const checkTypeUtil = {}
types.forEach((type)=>{
    checkTypeUtil[`is${type}`] = curring(isType,type)
})
export {
 checkTypeUtil
}
console.log(checkTypeUtil.isArray([]))

5. 用Array.isArray判斷數(shù)組

上邊提到 instanceof可以用來檢測(cè)數(shù)組,但是這在iframe創(chuàng)建的多window環(huán)境中,因?yàn)閣indow全局環(huán)境需要隔離,所以Array和Array.prototype在每個(gè)窗口中必須是不同的,所以iframeA.Array.prototype ≠ iframeB.Array.prototype,所以 iframeA.arr instanceof iframeB.Array必定是返回false,這是小概率的事件,但是在使用iframe的場(chǎng)景里,互相傳值,也是非??赡馨l(fā)生的。使用ES6提供的Array.isArray就沒有這個(gè)問題,可以準(zhǔn)確判斷數(shù)組。

可以這樣 pollify

if (!Array.isArray) {
  Array.isArray = function(x) {
    return Object.prototype.toString.call(x) === '[object Array]';
  };
}

6.區(qū)分ArrayLike與Array

類數(shù)組的定義是:

  • 擁有l(wèi)ength屬性,其它屬性(索引)為非負(fù)整數(shù)(對(duì)象中的索引會(huì)被當(dāng)做字符串來處理
  • 不具有數(shù)組所具有的方法
function isLikeArray(x){
    if(!(typeof x === 'object' && x !== null)){
        return false
    }
    return typeof x.length === 'number' && x.length >= 0 && !Array.isArray(x)
}

類數(shù)組可以用Array.from Array.prototype.slice.call(val)來轉(zhuǎn)換為真正的數(shù)組。

7.判斷一個(gè)對(duì)象是否是純對(duì)象(or普通對(duì)象)

純對(duì)象的定義:特指通過一下三種方式創(chuàng)建的對(duì)象

  • new Object
  • 對(duì)象字面量創(chuàng)建 {}
  • Object.create(null)

jquery、lodash源碼都是采用下邊的方法來檢測(cè)

const funcToString = Function.prototype.toString
const objectCtorString = funcToString.call(Object)

function isPlainObject(value){
    // 先用toString先排除其他數(shù)據(jù)類型
    if(!value || !Object.prototype.toString.call(value) === "[object Object]"){
        return false
    }
    const proto = Object.getPrototypeOf(value)
    if(proto === null){//兼容Object.create(null)這樣創(chuàng)建的對(duì)象
        return true
    }
    const Ctor = Object.prototype.hasOwnProperty.call(proto,'constructor') && proto.constructor;
    if(typeof Ctor !== 'function'){
        return false
    }
    // 這里通過字符串判斷構(gòu)造函數(shù)是否是Object,而不是直接使用instanceof,是為了避免上邊提到的 多window環(huán)境Object不同的問題
    if(funcToString.call(Ctor) === objectCtorString){
        return true
    }
    return false
}
console.log(isPlainObject(Object.create(null)))
console.log(isPlainObject(new Object))
console.log(isPlainObject({a:1}))

8. NaN如何檢測(cè),Number.isNaN與isNaN有啥區(qū)別

結(jié)論:Number.isNaN會(huì)嚴(yán)格的判斷傳入的值是否是直接等于NaN。

isNaN則會(huì)先進(jìn)行Number()轉(zhuǎn)換,然后再進(jìn)行是否是NaN的判斷。

9. 鴨式類型檢測(cè)法

其實(shí)上邊利用constuctor判斷數(shù)據(jù)類型,就是采用了這種方法。判斷一個(gè)動(dòng)物是不是鴨子,那么通過看起來像鴨子,叫起來像鴨子這樣簡(jiǎn)單的經(jīng)驗(yàn)判斷就可大致進(jìn)行判斷。

比如判斷一個(gè)對(duì)象是不是一個(gè)Promise,就可以這樣

function isPromise(x){
    if(!(x instanceof Promise)){
        return false
    }
    return typeof x.then === 'function'
}

總結(jié)

到此這篇關(guān)于JS數(shù)據(jù)類型檢測(cè)的文章就介紹到這了,更多相關(guān)JS數(shù)據(jù)類型檢測(cè)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論