Object.prototype:判斷對(duì)象類(lèi)型的方式
數(shù)據(jù)類(lèi)型的判斷是一個(gè)老生長(zhǎng)談的問(wèn)題了,不多廢話,直接先說(shuō)最優(yōu)的方法。
Object.prototype.toString.call
Object.prototype.toString.call()是 JavaScript 中用于準(zhǔn)確判斷數(shù)據(jù)類(lèi)型的方法。
toString()本身是Object原型上的一個(gè)方法,用于返回對(duì)象的字符串表示形式。而通過(guò)call()方法可以改變toString()執(zhí)行時(shí)的this指向,讓我們能夠獲取任意對(duì)象準(zhǔn)確的類(lèi)型信息。
如果你需要判斷一個(gè)數(shù)據(jù)是否是一個(gè)普通的對(duì)象而不是數(shù)組、函數(shù)等其他類(lèi)型,推薦使用 Object.prototype.toString.call 方法。
且無(wú)論對(duì)于基本數(shù)據(jù)類(lèi)型,還是復(fù)雜數(shù)據(jù)類(lèi)型,都是準(zhǔn)確有效的。
function isPlainObject(obj) {
return Object.prototype.toString.call(obj) === '[object Object]';
}
// 測(cè)試代碼
console.log(isPlainObject({})); // true
console.log(isPlainObject([])); // false
console.log(isPlainObject(function() {})); // false
下面再聊聊其它幾種方法,了解即可。
typeof
優(yōu)點(diǎn):
簡(jiǎn)單快速:是 JavaScript 原生提供的操作符,語(yǔ)法簡(jiǎn)單,易于理解和使用。對(duì)于基本數(shù)據(jù)類(lèi)型的判斷非常直接,如typeof 1返回"number",typeof "string"返回"string",typeof true返回"boolean",能快速區(qū)分這些常見(jiàn)的基本類(lèi)型。
兼容性好:在各種 JavaScript 環(huán)境中都能穩(wěn)定使用,幾乎所有的瀏覽器和 JavaScript 運(yùn)行時(shí)都支持typeof操作符,在代碼的跨平臺(tái)和跨瀏覽器場(chǎng)景中不用擔(dān)心兼容性問(wèn)題。
缺點(diǎn):
對(duì)復(fù)雜對(duì)象類(lèi)型判斷不準(zhǔn)確:對(duì)于復(fù)雜的數(shù)據(jù)類(lèi)型,typeof的判斷能力有限。例如,typeof []返回"object",不能準(zhǔn)確地識(shí)別出這是一個(gè)數(shù)組;typeof new Date()也返回"object",無(wú)法區(qū)分出是日期對(duì)象;typeof /abc/同樣返回"object",不能判斷是正則表達(dá)式。這在需要精確判斷復(fù)雜對(duì)象類(lèi)型的場(chǎng)景中會(huì)導(dǎo)致問(wèn)題。
無(wú)法判斷自定義對(duì)象類(lèi)型:如果是自定義的構(gòu)造函數(shù)創(chuàng)建的對(duì)象,typeof只能返回"object",不能提供關(guān)于該對(duì)象具體構(gòu)造函數(shù)的信息。例如,function Person() {}; var p = new Person(); typeof p返回"object",不能判斷這個(gè)對(duì)象是由Person構(gòu)造函數(shù)創(chuàng)建的。
constructor
優(yōu)點(diǎn):
能夠識(shí)別對(duì)象的構(gòu)造函數(shù):可以直接獲取創(chuàng)建對(duì)象的構(gòu)造函數(shù)。例如,[].constructor返回Array函數(shù),new Date().constructor返回Date函數(shù),(/abc/).constructor返回RegExp函數(shù)。對(duì)于自定義構(gòu)造函數(shù)創(chuàng)建的對(duì)象也能準(zhǔn)確識(shí)別,如function Person() {}; var p = new Person(); p.constructor返回Person函數(shù),這有助于明確對(duì)象的來(lái)源。
缺點(diǎn):
可被篡改:對(duì)象的constructor屬性是可以被修改的,這可能導(dǎo)致錯(cuò)誤的判斷。例如,var arr = []; arr.constructor = function() {}; arr.constructor就不再指向Array函數(shù),使得基于constructor的類(lèi)型判斷失效。
對(duì)于原始數(shù)據(jù)類(lèi)型有局限性:原始數(shù)據(jù)類(lèi)型本身沒(méi)有constructor屬性(在 JavaScript 中,原始數(shù)據(jù)類(lèi)型在某些操作下會(huì)進(jìn)行自動(dòng)裝箱,如1..constructor會(huì)返回Number函數(shù),但這種方式不夠直觀和穩(wěn)定),在判斷原始數(shù)據(jù)類(lèi)型時(shí)不是很方便,不如typeof直接。
instanceof
優(yōu)點(diǎn):
基于原型鏈判斷對(duì)象關(guān)系:可以準(zhǔn)確判斷一個(gè)對(duì)象是否是某個(gè)構(gòu)造函數(shù)的實(shí)例,是基于對(duì)象的原型鏈進(jìn)行判斷的。例如,[] instanceof Array返回true,new Date() instanceof Date返回true,能很好地判斷對(duì)象與構(gòu)造函數(shù)之間的繼承關(guān)系。在面向?qū)ο缶幊毯吞幚韺?duì)象實(shí)例關(guān)系的場(chǎng)景中非常有用。
缺點(diǎn):
受原型鏈影響易出錯(cuò):如果對(duì)象的原型鏈被修改,可能會(huì)導(dǎo)致錯(cuò)誤的判斷。例如,如果有一個(gè)對(duì)象obj,手動(dòng)將其原型設(shè)置為Array.prototype,那么obj instanceof Array會(huì)返回true,但實(shí)際上這個(gè)對(duì)象可能并不是按照常規(guī)方式通過(guò)Array構(gòu)造函數(shù)創(chuàng)建的。
不能用于判斷原始數(shù)據(jù)類(lèi)型:instanceof只能用于判斷對(duì)象是否是某個(gè)構(gòu)造函數(shù)的實(shí)例,對(duì)于原始數(shù)據(jù)類(lèi)型(如數(shù)字、字符串、布爾值等)不能進(jìn)行判斷,因?yàn)樵紨?shù)據(jù)類(lèi)型不是對(duì)象,沒(méi)有原型鏈的概念。例如,instanceof Number在嚴(yán)格意義上不符合instanceof的使用規(guī)則,返回的結(jié)果可能會(huì)讓人誤解(實(shí)際上在 JavaScript 內(nèi)部對(duì)原始數(shù)據(jù)類(lèi)型進(jìn)行自動(dòng)裝箱等操作時(shí),instanceof Number返回false)。