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

JavaScript獲取數(shù)據(jù)類(lèi)型的方法詳解

 更新時(shí)間:2024年02月05日 08:32:38   作者:FeCoder  
這篇文章給大家介紹了JavaScript獲取數(shù)據(jù)類(lèi)型的方法,文中所介紹的所有知識(shí)點(diǎn)、代碼示例以及提供的解決方案,均不考慮?IE?瀏覽器,僅支持最新版本的?Chrome、Firefox、Edge?和?Safari?瀏覽器,需要的朋友可以參考下

說(shuō)明

本文所介紹的所有知識(shí)點(diǎn)、代碼示例以及提供的解決方案,均不考慮 IE 瀏覽器,僅支持最新版本的 ChromeFirefox、Edge 和 Safari 瀏覽器。

概述

前端開(kāi)發(fā)過(guò)程中一個(gè)常見(jiàn)的功能是:檢測(cè)某個(gè)數(shù)據(jù)屬于什么類(lèi)型,是字符串、數(shù)字、數(shù)組、還是對(duì)象等等。比如,我們定義了一個(gè)函數(shù),并且支持傳參,往往就需要對(duì)傳入的參數(shù)進(jìn)行數(shù)據(jù)類(lèi)型檢測(cè),然后根據(jù)檢測(cè)結(jié)果進(jìn)行相應(yīng)的處理,這時(shí)我們就必須知道如何準(zhǔn)確的獲取數(shù)據(jù)的類(lèi)型。在構(gòu)思解決方案之前,我們首先需要回顧一下基礎(chǔ)知識(shí),那就是在 JavaScript 中到底有幾種數(shù)據(jù)類(lèi)型?

數(shù)據(jù)類(lèi)型種類(lèi)

這里所講的數(shù)據(jù)類(lèi)型指的是 JavaScript 語(yǔ)言層面的數(shù)據(jù)類(lèi)型,截至目前,共有 8 種類(lèi)型,可分為【基本數(shù)據(jù)類(lèi)型】和【引用數(shù)據(jù)類(lèi)型】:

基本數(shù)據(jù)類(lèi)型

  • 字符串( String
  • 數(shù)字( Number
  • 布爾值 ( Boolean
  • null
  • undefined
  • Symbol
  • BigInt

引用數(shù)據(jù)類(lèi)型

  • 對(duì)象( Object, Array 等等 )

區(qū)別

上面提到的【基本數(shù)據(jù)類(lèi)型】和【引用數(shù)據(jù)類(lèi)型】有什么區(qū)別呢?

基本數(shù)據(jù)類(lèi)型的值是保存在 “棧” 內(nèi)存中的,它是可以直接訪問(wèn)的,所有的讀寫(xiě)操作都是直接作用于數(shù)據(jù)本身,中間沒(méi)有任何 “轉(zhuǎn)接” 行為。

引用數(shù)據(jù)類(lèi)型的值是保存在 “堆” 內(nèi)存中的,在 JavaScript 中是不允許直接訪問(wèn)堆內(nèi)存中的數(shù)據(jù)的,要想訪問(wèn)就需要拿到它在堆內(nèi)存中的地址,然后通過(guò)這個(gè)地址進(jìn)行讀寫(xiě)操作。

舉個(gè)例子:張三要跟李四溝通事情,基本數(shù)據(jù)類(lèi)型就相當(dāng)于,張三直接跟李四本人交流。而引用數(shù)據(jù)類(lèi)型則相當(dāng)于張三要跟 “代理人” 溝通,再由這個(gè) “代理人” 把張三的需求轉(zhuǎn)述給李四,李四如有反饋,也必須通過(guò) “代理人” 轉(zhuǎn)告給張三,張三和李四由始至終都不能直接溝通。

檢測(cè)方法

typeof 運(yùn)算符

這是最簡(jiǎn)單也是最常用的數(shù)據(jù)類(lèi)型檢測(cè)方法,但同時(shí)它也不太 “靠譜”,為什么這樣說(shuō)呢?可以先看看下面的代碼示例:

console.log( typeof "data" );          // string
console.log( typeof 123456 );          // number
console.log( typeof true );            // boolean
console.log( typeof function () {} );  // function
console.log( typeof Symbol() );        // symbol
console.log( typeof 100n );            // bigint
console.log( typeof undefined );       // undefined

console.log( "===================================" );

console.log( typeof null );            // object
console.log( typeof { a: "a" } );      // object    
console.log( typeof [ 1, 2, 3 ] );     // object

可以看到,對(duì)于前七種數(shù)據(jù),能檢測(cè)出相應(yīng)的類(lèi)型,而后三種卻一律返回 object。前面曾提到,ArrayObject 都屬于引用數(shù)據(jù)類(lèi)型,而 null 被認(rèn)為是對(duì)空對(duì)象的引用,也歸屬于 Object 范疇,由此可見(jiàn),typeof 是無(wú)法區(qū)分出引用數(shù)據(jù)類(lèi)型的。

上面的示例中還有一個(gè)關(guān)鍵點(diǎn),那就是 function 函數(shù)。函數(shù)實(shí)際上也是對(duì)象,它并不代表一種數(shù)據(jù)類(lèi)型,但它卻非常特殊。函數(shù)擁有對(duì)象的所有能力,但同時(shí)它自身還擁有特殊的屬性,并且與對(duì)象相比,函數(shù)還有一個(gè)特殊之處,就是它是可調(diào)用的,你可以手動(dòng)調(diào)用函數(shù)去執(zhí)行某個(gè)操作?;谝陨咸厥馇闆r,在 ECMAScript 規(guī)范中規(guī)定了可以通過(guò) typeof 區(qū)分出函數(shù)和其它對(duì)象。

除了上述能檢測(cè)出的七種類(lèi)型之外,幾乎其它所有類(lèi)型經(jīng) typeof 檢測(cè)后都是返回 object,例如:

console.log( typeof document.children );                 // object
console.log( typeof window );                            // object
console.log( typeof document.querySelector( "html" ) );  // object
console.log( typeof document.createElement( "div" ) );   // object
console.log( typeof new Map() );                         // object    
console.log( typeof new Set() );                         // object
console.log( typeof new Promise( () => {} ) );           // object

至此,可以得到一個(gè)初步結(jié)論,使用 typeof 運(yùn)算符只能檢測(cè)出:字符串、數(shù)字、布爾值、函數(shù)、Symbol、BigIntundefined 七種類(lèi)型,對(duì)于數(shù)組、對(duì)象、null 和其它類(lèi)型則無(wú)能為力,需要另尋他法。

這里還需要說(shuō)明一個(gè)特殊情況,對(duì)于字符串、數(shù)字、布爾值這三種基本數(shù)據(jù)類(lèi)型,還存在對(duì)應(yīng)的特殊引用類(lèi)型:

  • new String()
  • new Number()
  • new Boolean()
console.log( ( new String( "aa" ) ).valueOf() === "aa" );   // true
console.log( ( new Number( 1234 ) ).valueOf() === 1234 );   // true
console.log( ( new Boolean( true ) ).valueOf() === true );  // true

因此,一旦通過(guò)上述的方式創(chuàng)建字符串、數(shù)字或者布爾值,使用 typeof 將無(wú)法得到準(zhǔn)確的類(lèi)型:

console.log( typeof new String( "aa" ) );   // object
console.log( typeof new Number( 1234 ) );   // object
console.log( typeof new Boolean( true ) );  // object

由此可見(jiàn),typeof 運(yùn)算符對(duì)于字符串、數(shù)字和布爾值的類(lèi)型判定,無(wú)法做到百分百的絕對(duì)精準(zhǔn)。不過(guò),在實(shí)際開(kāi)發(fā)中,基本上極少會(huì)遇到使用上述特殊方式創(chuàng)建這三種數(shù)據(jù)類(lèi)型的情況。因此,仍然可以繼續(xù)使用 typeof 進(jìn)行判斷。

instanceof 運(yùn)算符

以下是 MDN 關(guān)于 instanceof 的描述:

instanceof運(yùn)算符用于檢測(cè)構(gòu)造函數(shù)的 prototype 屬性是否出現(xiàn)在某個(gè)實(shí)例對(duì)象的原型鏈上。

語(yǔ)法:obj instanceof constructor

由于 instanceof 是基于 ”原型“ 的,因此它只適用于檢測(cè)引用數(shù)據(jù)類(lèi)型,如:對(duì)象、數(shù)組等。

我們先來(lái)看一下示例:

const obj = {
    a: "a"
};
console.log( obj instanceof Object );  // true
console.log( Object.getPrototypeOf( obj ) === Object.prototype );  // true

在上面的示例中,obj 是一個(gè)通過(guò)字面量形式創(chuàng)建的對(duì)象,本質(zhì)上相當(dāng)于 new Object(),也就是說(shuō),obj 是由 Object() 構(gòu)造函數(shù)構(gòu)建出來(lái)的,那么 obj 的原型鏈上必然包含 Object 的原型。

再看一個(gè)數(shù)組的例子:

const arr = [ 1, 2, 3 ];
console.log( arr instanceof Array );  // true

同樣的原理,arr 是一個(gè)通過(guò)字面量形式創(chuàng)建的數(shù)組,本質(zhì)上相當(dāng)于 new Array(),那 arr 的原型鏈上也必然包含 Array 的原型,因此,上面的邏輯是沒(méi)問(wèn)題的,但是如果對(duì)代碼稍加改造,將 Array 換成 Object 會(huì)是什么結(jié)果呢?

const arr = [ 1, 2, 3 ];
console.log( arr instanceof Object );  // true

結(jié)果顯示也為 true,這是因?yàn)樵?JavaScript 中,數(shù)組其實(shí)也是對(duì)象,不僅僅是數(shù)組,凡是通過(guò) new 關(guān)鍵字創(chuàng)建的實(shí)例本質(zhì)上都是對(duì)象。所以,前文提到的 typeof new xxx 的結(jié)果都是 object。也正因如此,數(shù)組的原型鏈中也必然包含 Object 的原型。

另外需要說(shuō)明的是,instanceof 在多 iframe 環(huán)境下會(huì)存在問(wèn)題,因?yàn)檫@意味著存在多個(gè)全局環(huán)境,而不同的全局環(huán)境擁有不同的全局對(duì)象,從而擁有不同的內(nèi)置類(lèi)型構(gòu)造函數(shù),這將會(huì)導(dǎo)致 instanceof 出現(xiàn)混亂。

Object.prototype.toString.call()

這種絕妙的檢測(cè)方式最早是由 ”始祖級(jí)“ 的 JavaScript 類(lèi)庫(kù) Prototype.js 發(fā)掘出來(lái)的。這幾乎要追溯到近 20 年前了,那時(shí)的前端還處在萌芽時(shí)期,各種規(guī)范標(biāo)準(zhǔn)尚未完善,還要面對(duì)令人抓狂的瀏覽器兼容問(wèn)題,因此要想準(zhǔn)確檢測(cè)出各種數(shù)據(jù)類(lèi)型簡(jiǎn)直是難如登天。各大程序庫(kù)想盡了辦法,各種奇技淫巧層出不窮,直到這種方式的出現(xiàn),終于有了一個(gè)穩(wěn)定的檢測(cè)方式,之后的庫(kù)和框架也基本都是用此方法來(lái)檢測(cè)數(shù)據(jù)類(lèi)型。

它的根本原理實(shí)際上就是輸出對(duì)象內(nèi)部的類(lèi)屬性 [[Class]] 的值,這在絕大多數(shù)情況下是肯定準(zhǔn)確的。這里先看第一個(gè)知識(shí)點(diǎn):toString。

簡(jiǎn)單來(lái)說(shuō),toString 方法就是將對(duì)象以字符串的形式返回。JavaScript 中幾乎所有對(duì)象都有 toString 方法,nullundefined 沒(méi)有 toString 方法,下面通過(guò)代碼示例看一下每種類(lèi)型調(diào)用 toString 后返回的結(jié)果:

console.log( ( new String( "a" ) ).toString() );    // a
console.log( ( new Number( 100 ) ).toString() );    // 100
console.log( ( new Boolean( true ) ).toString() );  // true
console.log( [ 1,2,3 ].toString() );                // 1,2,3
console.log( { a: "a" }.toString() );               // [object Object]
console.log( Symbol().toString() );                 // Symbol()
console.log( 100n.toString() );                     // 100

上述結(jié)果可以看出,每個(gè)對(duì)象的 toString 方法都有自己的一套邏輯, 因此輸出的結(jié)果不盡相同,并且上面的結(jié)果也說(shuō)明了,單純使用各自的 toString 方法得到的值也沒(méi)能表示出相關(guān)類(lèi)型,只有一個(gè) [object Object] 值得研究。

為什么會(huì)得到 [object Object] 呢?這是因?yàn)閷?duì)象的 toString 方法無(wú)法將對(duì)象正確解析為字符串,所以 JavaScript 引擎直接返回了字符串 [object Object]。此時(shí)我們可以做出一個(gè)這樣的假設(shè):因?yàn)槭窃?object 類(lèi)型的數(shù)據(jù)上調(diào)用了 toString 方法,返回了 [object Object],而這個(gè)字符串中的兩個(gè)單詞都是 object(先不考慮大小寫(xiě)),能否說(shuō)明這個(gè)字符串實(shí)際已經(jīng)包含了類(lèi)型信息呢?如果這個(gè)假設(shè)成立,那么理論上其它類(lèi)型的數(shù)據(jù)應(yīng)該也可以通過(guò)這種方式獲取到類(lèi)型。但是前面提到了,每個(gè)對(duì)象的 toString 方法都有自己的一套邏輯,返回的內(nèi)容五花八門(mén),現(xiàn)在就需要想辦法讓它們也能返回類(lèi)似 [object Object] 這種形式的字符串,以此來(lái)推斷其所屬類(lèi)型。這里就需要用到原型屬性,因?yàn)樗械膶?duì)象都繼承自 Object,既然它們各自的 toString 方法有自己的邏輯,那我們就不用他們自身的 toString,而是使用繼承自 Object 原型上的 toString, 也就是 Object.prototype.toString,那為什么后面還用了一個(gè) call 呢? 先來(lái)看一下不用 call 的結(jié)果:

console.log( Object.prototype.toString( [] ) );    // [object Object] 
console.log( Object.prototype.toString( {} ) );    // [object Object]
console.log( Object.prototype.toString( "aa" ) );  // [object Object]
console.log( Object.prototype.toString( 11 ) );    // [object Object]

單純使用 Object.prototype.toString 將一律返回 [object Object],因?yàn)檫@始終是在調(diào)用 ObjecttoString 方法,其內(nèi)部的 this 始終指向的是 Object,所以就必須要借助 call 改變 this 的指向( apply 也可以 ), 所以才有了 Object.prototype.toString.call() 的寫(xiě)法。其實(shí)可以這樣理解:我自己的 toString 被我重寫(xiě)了,不能用了,那我就用 ObjecttoString,因?yàn)樗窃技儍舻?,能返回我想要的東西,并且我繼承自 Object,能借用它的一切,自然也就能借用它的 toString,只需在借用時(shí)注明是我在使用就可以了( call 的作用 )。

下面就看看使用 Object.prototype.toString.call() 到底能否返回我們想要的結(jié)果吧。

console.log( Object.prototype.toString.call( "aa" ) );            // [object String]
console.log( Object.prototype.toString.call( 1000 ) );            // [object Number]
console.log( Object.prototype.toString.call( true ) );            // [object Boolean]
console.log( Object.prototype.toString.call( 100n ) );            // [object BigInt]
console.log( Object.prototype.toString.call( null ) );            // [object Null]
console.log( Object.prototype.toString.call( undefined ) );       // [object Undefined]
console.log( Object.prototype.toString.call( Symbol() ) );        // [object Symbol]
console.log( Object.prototype.toString.call( [ 1,2,3 ] ) );       // [object Array]
console.log( Object.prototype.toString.call( { a: "a" } ) );      // [object Object]
console.log( Object.prototype.toString.call( function () {} ) );  // [object Function]

再看看其它類(lèi)型的數(shù)據(jù)

// [object Promise]
console.log( Object.prototype.toString.call( new Promise( () => {} ) ) ); 

// [object HTMLHtmlElement]
console.log( Object.prototype.toString.call( document.querySelector( "html" ) ) );

// [object HTMLDivElement]
console.log( Object.prototype.toString.call( document.createElement( "div" ) ) );

// [object HTMLCollection]
console.log( Object.prototype.toString.call( document.children ) );

// [object HTMLDocument]
console.log( Object.prototype.toString.call( document ) );

// [object Window]
console.log( Object.prototype.toString.call( window ) );

// [object Set]
console.log( Object.prototype.toString.call( new Set() ) );

// [object Map]
console.log( Object.prototype.toString.call( new Map() ) );

根據(jù)以上結(jié)果可以得知,返回結(jié)果都是以 [object 開(kāi)頭,以 類(lèi)型] 結(jié)尾,那么我們加工一下就可以用它直接返回類(lèi)型了:

Object.prototype.toString.call( obj ).slice( 8, -1 );

那這個(gè)方法真的絕對(duì)保險(xiǎn)嗎?99% 的情況下是保險(xiǎn)的,但不排除極特殊情況,比如:

Object.prototype.toString = () => "哈哈哈";

console.log( Object.prototype.toString.call( "aa" ) );  // 哈哈哈
console.log( Object.prototype.toString.call( 1000 ) );  // 哈哈哈
console.log( Object.prototype.toString.call( true ) );  // 哈哈哈
console.log( Object.prototype.toString.call( 100n ) );  // 哈哈哈

由此可見(jiàn),如果最原始的 Object.prototype.toString 被改寫(xiě)了,那么這個(gè)方法就失效了,不過(guò)正常情況下誰(shuí)會(huì)這樣做呢?

封裝示例

基于以上各種檢測(cè)手段,我們可以封裝一個(gè)基本的類(lèi)型檢測(cè)方法,下面是一個(gè)最基本的封裝示例,大家可以自行完善。

function getType ( data ) {
    
    // 對(duì)于簡(jiǎn)單的類(lèi)型直接使用 typeof 判斷
    let type = "";
    switch ( typeof data ) {
        case "string":    type === "string";    break;
        case "number":    type === "number";    break;
        case "boolean":   type === "boolean";   break;
        case "function":  type === "function";  break;
        case "symbol":    type === "symbol";    break;
        case "bigint":    type === "bigint";    break;
        case "undefined": type === "undefined"; break;
    }
    if ( type ) {
        return type;
    }

    // 數(shù)組類(lèi)型直接使用原生提供的 Array.isArray
    if ( Array.isArray( data ) ) {
        return "array";
    }

    // 其余類(lèi)型使用 Object.prototype.toString.call 獲取
    return Object.prototype.toString.call( data ).slice( 8, -1 ).toLowerCase();
}

以上就是JavaScript獲取數(shù)據(jù)類(lèi)型的方法詳解的詳細(xì)內(nèi)容,更多關(guān)于JavaScript獲取數(shù)據(jù)類(lèi)型的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論