今天要分享的問(wèn)題就是:如何在JS中檢查一個(gè)變量的類型?
先上結(jié)論:
如果判斷的是基本數(shù)據(jù)類型或JavaScript內(nèi)置對(duì)象,使用toString;如果要判斷的是自定義類型,請(qǐng)使用instanceof。
在 ECMAScript 規(guī)范中,共定義了 7 種數(shù)據(jù)類型,分為 基本類型 和 引用類型 兩大類。
基本類型 也稱為簡(jiǎn)單類型,按值訪問(wèn)。
引用類型 也稱為復(fù)雜類型,按址訪問(wèn)。
JavaScript內(nèi)置了一些引用類型,如圖所示:
JavaScript的變量是松散類型。雖然這使得提供類型信息的方式更加靈活了,但也容易誤用。
下面來(lái)分析常見的四種JavaScript類型檢查方法:typeof
, instanceof
, constructor
, toString
。
typeof
typeof
是一個(gè)操作符,其右側(cè)跟一個(gè)一元表達(dá)式,并返回這個(gè)表達(dá)式的數(shù)據(jù)類型。
它返回的結(jié)果用該類型的字符串(全小寫字母)形式表示。返回值有7種取值:number
、boolean
、symbol
、string
、undefined
、object
和function
。
typeof 3; // number 有效
typeof true; //boolean 有效
typeof Symbol(); // symbol 有效
typeof ''; // string 有效
typeof undefined; //undefined 有效
typeof null; //object 無(wú)效
typeof [] ; //object 無(wú)效
typeof new Function(); // function 有效
typeof new Date(); //object 無(wú)效
typeof new RegExp(); //object 無(wú)效
有些時(shí)候,typeof
操作符會(huì)返回一些令人迷惑但技術(shù)上卻正確的值:
- 對(duì)于基本類型 ,除
null
以外,均可以返回正確的結(jié)果。 - 對(duì)于引用類型 ,除
function
以外,一律返回object
類型。 - 對(duì)于
null
,返回object
類型。這是一個(gè)知名的bug。由于影響范圍越來(lái)越大,就沒(méi)有修復(fù)了。 - 對(duì)于
function
函數(shù),返回 function 類型。從技術(shù)角度講,函數(shù)在ECMAScript中是對(duì)象,不是一種數(shù)據(jù)類型。然而,函數(shù)也確實(shí)有一些特殊的屬性,因此通過(guò)typeof操作符來(lái)區(qū)分函數(shù)和其他對(duì)象是有必要的。
由上可以得出:typeof
對(duì)引用類型 操作的返回值不是我們想要的結(jié)果。
instanceof
instanceof
是用來(lái)判斷 A 是否為 B 的實(shí)例的。它的表達(dá)式為:A instanceof B
。
如果 A 是 B 的實(shí)例,則返回 true,否則返回 false。 在這里需要特別注意的是:instanceof
斷規(guī)則是某個(gè)對(duì)象的原型鏈?zhǔn)欠癜硞€(gè)構(gòu)造函數(shù)的prototype屬性
。
let arr = [];
arr instanceof Array; // true
arr instanceof Object; // true
看看arr原型鏈簡(jiǎn)圖:
arr的 __proto__
直接指向Array.prototype
,間接指向 Object.prototype
,所以按照 instanceof
的判斷規(guī)則,[] 就是Array的實(shí)例,也是Object的實(shí)例。instanceof
返回值都是true
。
依此類推,RegExp
, Object
, Function
也會(huì)形成一條對(duì)應(yīng)的原型鏈 。
/abc/ instanceof RegExp // true
({}) instanceof Object // true
(function(){}) instanceof Function // true
instanceof
是通過(guò)原型鏈來(lái)檢查類型的,所以適用于任何"object"的類型檢查。自定義的類型同樣滿足。
// 比如直接原型關(guān)系
function Fruit(){ }
(new Fruit) instanceof Fruit // true
// 原型鏈上的間接原型
function Apple(){}
Apple.prototype = new Fruit
(new Apple) instanceof Fruit // true
注意instanceof
對(duì)基本數(shù)據(jù)類型 不起作用,因?yàn)榛緮?shù)據(jù)類型沒(méi)有原型鏈。
3 instanceof Number // false
true instanceof Boolean // false
'abc' instanceof String // false
null instanceof String // always false
undefined instanceof String // always false
但你可以這樣:
new Number(3) instanceof Number // true
new Boolean(true) instanceof Boolean // true
new String('abc') instanceof String // true
但這時(shí)你已經(jīng)知道數(shù)據(jù)類型了,類型檢查已經(jīng)沒(méi)有意義了。
使用constructor屬性
constructor
屬性返回一個(gè)指向創(chuàng)建了該對(duì)象原型的函數(shù)引用。需要注意的是,該屬性的值是那個(gè)函數(shù)本身。例如:
function Fruit(){}
var a = new Fruit
a.constructor === Fruit // true
constructor不適合用來(lái)判斷變量類型。
- 其一,它是一個(gè)屬性,非常容易被偽造:
var a = new Fruit
a.constructor === Array
a.constructor === Fruit // false
- 其二,
constructor
指向的是最初創(chuàng)建當(dāng)前對(duì)象的函數(shù),是原型鏈最上層的那個(gè)方法:
function Apple(){}
Apple.prototype = new Fruit
function BadApple(){}
BadApple.prototype = new Apple
(new BadApple).constructor === Fruit // true
Fruit.constructor === Function // true
與instanceof類似,constructor只能用于檢測(cè)引用對(duì)象,對(duì)基本數(shù)據(jù)類型無(wú)能為力。
與instanceof不同的是,在訪問(wèn)基本數(shù)據(jù)類型的屬性時(shí),JavaScript會(huì)自動(dòng)調(diào)用其構(gòu)造函數(shù)來(lái)生成一個(gè)對(duì)象。例如:
(3).constructor === Number // true
true.constructor === Boolean // true
'abc'.constructor === String // true
// 相當(dāng)于
(new Number(3)).constructor === Number
(new Boolean(true)).constructor === Boolean
(new String('abc')).constructor === String
這種將一個(gè)值類型轉(zhuǎn)換為對(duì)象引用類型的機(jī)制在其他語(yǔ)言中也存在,稱為裝箱
。
但在基本數(shù)據(jù)類型中,null
和undefined
調(diào)用constructor
會(huì)拋出TypeError異常。
null.constructor // TypeError!
undefined.constructor // TypeError!
因?yàn)?code>null是JavaScript原型鏈的起點(diǎn),undefined
是無(wú)效對(duì)象,都沒(méi)有構(gòu)造函數(shù),也就不存在constructor
屬性。
instanceof跨窗口問(wèn)題
我們知道Javascript是運(yùn)行在宿主環(huán)境下的,而每個(gè)宿主環(huán)境會(huì)提供一套ECMA標(biāo)準(zhǔn)的內(nèi)置對(duì)象,以及宿主對(duì)象(如window, document),一個(gè)新的窗口即是一個(gè)新的宿主環(huán)境。 不同窗口下的內(nèi)置對(duì)象是不同的實(shí)例,擁有不同的內(nèi)存地址。
而instanceof
和constructor
都是通過(guò)比較兩個(gè)Function是否相等來(lái)進(jìn)行類型判斷的。 此時(shí)顯然會(huì)出問(wèn)題,例如:
var iframe = document.createElement('iframe');
var iWindow = iframe.contentWindow;
document.body.appendChild(iframe);
iWindow.Array === Array // false
// 相當(dāng)于
iWindow.Array === window.Array // false
因此iWindow中的數(shù)組arr原型鏈上是沒(méi)有window.Array的。請(qǐng)看:
iWindow.document.write('<script> var arr = [1, 2]</script>');
iWindow.arr instanceof Array // false
iWindow.arr instanceof iWindow.Array // true
使用toString方法
使用toString
方法是最為可靠的類型檢測(cè)手段,它會(huì)將當(dāng)前對(duì)象類型轉(zhuǎn)換為字符串并輸出。
toString
屬性定義在Object.prototype上,因而所有對(duì)象都擁有toString方法。但Array
, Date
等對(duì)象會(huì)重寫從Object.prototype繼承來(lái)的toString,所以最好用Object.prototype.toString來(lái)檢測(cè)類型。
toString = Object.prototype.toString;
toString.call(new Date); // [object Date]
toString.call(new String);// [object String]
toString.call(Math); // [object Math]
toString.call(3); // [object Number]
toString.call([]); // [object Array]
toString.call({}); // [object Object]
// Since JavaScript 1.8.5
toString.call(undefined); // [object Undefined]
toString.call(null); // [object Null]
采用toString
也不是完美的,它無(wú)法檢測(cè)用戶自定義類型。因?yàn)镺bject.prototype是不知道用戶會(huì)創(chuàng)造什么類型的,它只能檢測(cè)ECMA標(biāo)準(zhǔn)中的那些內(nèi)置類型。
toString.call(new Fruit) // [object Object]
因?yàn)榉祷刂凳亲址脖苊饬丝绱翱趩?wèn)題。當(dāng)然IE彈窗中還是有Bug,不必管它了。 現(xiàn)在多少人還在用IE?多少人還在用彈窗?
和Object.prototype.toString類似地,F(xiàn)unction.prototype.toString也有類似功能,不過(guò)它的this只能是Function,其他類型(例如基本數(shù)據(jù)類型)都會(huì)拋出異常。
其他
有時(shí)Duck Typing的類型推斷方式也非??尚校菜埔呀?jīng)成為了前端的慣例。比如jQuery是這樣判斷一個(gè)Window的:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-481442.html
isWindow: function(obj){
return obj && typeof obj === 'object' && "setInterval" in obj;
}
總結(jié)
-
typeof
只能檢測(cè)基本數(shù)據(jù)類型,對(duì)于null
還有Bug; -
instanceof
適用于檢測(cè)對(duì)象,它是基于原型鏈運(yùn)作的; -
constructor
指向的是最初創(chuàng)建者,而且容易偽造,不適合做類型判斷; -
toString
適用于ECMA內(nèi)置JavaScript類型(包括基本數(shù)據(jù)類型和內(nèi)置對(duì)象)的判斷; - 引用類型 檢查都有跨窗口問(wèn)題,比如instanceof和constructor。
總之,如果你要判斷的是基本數(shù)據(jù)類型或JavaScript內(nèi)置對(duì)象,使用toString; 如果要判斷的是自定義類型,請(qǐng)使用instanceof。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-481442.html
到了這里,關(guān)于再也不用擔(dān)心變量類型錯(cuò)誤!學(xué)會(huì)JS中如何輕松檢查變量類型的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!