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