參考文章:數(shù)據(jù)類型
typeof 運(yùn)算符
JavaScript
有三種方法霹购,可以確定一個值到底是什么類型尿贫。
- typeof運(yùn)算符
- instanceof運(yùn)算符
- Object.prototype.toString方法
typeof
typeof
運(yùn)算符可以返回一個值的數(shù)據(jù)類型。
- 數(shù)值、字符串、布爾值分別返回
number
、string
尖飞、boolean
。
typeof 123 // "number"
typeof '123' // "string"
typeof false // "boolean"
- 函數(shù)返回
function
店雅。
function f() {}
typeof f
// "function"
-
undefined
返回undefined
政基。
typeof undefined
// "undefined"
利用這一點(diǎn),typeof
可以用來檢查一個沒有聲明的變量闹啦,而不報(bào)錯沮明。
v
// ReferenceError: v is not defined
typeof v
// "undefined"
上面代碼中,變量v
沒有用var
命令聲明窍奋,直接使用就會報(bào)錯荐健。但是,放在typeof
后面琳袄,就不報(bào)錯了江场,而是返回undefined
。
實(shí)際編程中窖逗,這個特點(diǎn)通常用在判斷語句址否。
// 錯誤的寫法
if (v) {
// ...
}
// ReferenceError: v is not defined
// 正確的寫法
if (typeof v === "undefined") {
// ...
}
- 對象返回
object
。
typeof window // "object"
typeof {} // "object"
typeof [] // "object"
typeof
缺點(diǎn):上面代碼中碎紊,空數(shù)組([])的類型也是object
佑附,這表示在 JavaScript
內(nèi)部,數(shù)組本質(zhì)上只是一種特殊的對象仗考。 typeof
無法區(qū)分數(shù)組和對象帮匾。
這里順便提一下,instanceof
運(yùn)算符可以區(qū)分?jǐn)?shù)組和對象痴鳄。
var o = {};
var a = [];
o instanceof Array // false
a instanceof Array // true
- null返回object。因?yàn)?code>null被認(rèn)為是一個空的對象的引用缸夹。
typeof null // "object"
instanceof
instanceof
運(yùn)算符返回一個布爾值痪寻,表示對象是否為某個構(gòu)造函數(shù)的實(shí)例。
- 下面代碼中虽惭,對象
v
是構(gòu)造函數(shù)Vehicle
的實(shí)例橡类,所以返回true
。
var v = new Vehicle();
v instanceof Vehicle // true
-
instanceof
運(yùn)算符的左邊是實(shí)例對象芽唇,右邊是構(gòu)造函數(shù)顾画。 -
instanceof
的作用:會檢查右邊構(gòu)造函數(shù)的原型對象(prototype
)取劫,是否在左邊對象的原型鏈上。因此研侣,下面兩種寫法是等價(jià)的谱邪。
v instanceof Vehicle
// 等同于
Vehicle.prototype.isPrototypeOf(v)
上面代碼中,Object.prototype.isPrototypeOf
的含義如下:
var p = {x:1};//定義一個原型對象
var o = Object.create(p);//使用這個原型創(chuàng)建一個對象
p.isPrototypeOf(o);//=>true:o繼承p
Object.prototype.isPrototypeOf(p);//=> true p繼承自O(shè)bject.prototype
- 由于
instanceof
檢查整個原型鏈庶诡,因此同一個實(shí)例對象惦银,可能會對多個構(gòu)造函數(shù)都返回true
。
var d = new Date();
d instanceof Date // true
d instanceof Object // true
上面代碼中末誓,d
同時(shí)是Date
和Object
的實(shí)例扯俱,因此對這兩個構(gòu)造函數(shù)都返回true
。
-
instanceof
的原理是檢查右邊構(gòu)造函數(shù)的prototype
屬性喇澡,是否在左邊對象的原型鏈上迅栅。有一種特殊情況,就是左邊對象的原型鏈上晴玖,只有null
對象读存。這時(shí),instanceof
判斷會失真窜醉。
var obj = Object.create(null);
typeof obj // "object"
Object.create(null) instanceof Object // false
上面代碼中宪萄,Object.create(null)
返回一個新對象obj
,它的原型是null
(Object.create的詳細(xì)介紹見后文)榨惰。右邊的構(gòu)造函數(shù)Object
的prototype
屬性拜英,不在左邊的原型鏈上,因此instanceof
就認(rèn)為obj
不是Object
的實(shí)例琅催。但是居凶,只要一個對象的原型不是null
,instanceof
運(yùn)算符的判斷就不會失真藤抡。
-
instanceof
運(yùn)算符的一個用處侠碧,是判斷值的類型。
var x = [1, 2, 3];
var y = {};
x instanceof Array // true
y instanceof Object // true
上面代碼中缠黍,instanceof
運(yùn)算符判斷弄兜,變量x
是數(shù)組,變量y
是對象瓷式。
缺點(diǎn):instanceof
運(yùn)算符只能用于對象(純對象和數(shù)組)替饿,不適用原始類型(Undefined、Null贸典、Boolean视卢、Number 和 String)的值。
var s = 'hello';
s instanceof String // false
上面代碼中廊驼,字符串不是String
對象的實(shí)例(因?yàn)樽址皇菍ο螅┚莨苑祷?code>false惋砂。
此外,對于undefined
和null
绳锅,instanceOf
運(yùn)算符總是返回false
西饵。
undefined instanceof Object // false
null instanceof Object // false
- 利用
instanceof
運(yùn)算符,還可以巧妙地解決榨呆,調(diào)用構(gòu)造函數(shù)時(shí)罗标,忘了加new
命令的問題。
function Fubar (foo, bar) {
if (this instanceof Fubar) {
this._foo = foo;
this._bar = bar;
} else {
return new Fubar(foo, bar);
}
}
上面代碼使用instanceof
運(yùn)算符积蜻,在函數(shù)體內(nèi)部判斷this
關(guān)鍵字是否為構(gòu)造函數(shù)Fubar
的實(shí)例闯割。如果不是,就表明忘了加new
命令竿拆。
Object.prototype.toString
- 要想?yún)^(qū)別對象宙拉、數(shù)組、函數(shù)單純使用
typeof
是不行的丙笋。null
和Array
的結(jié)果也是object
谢澈,有時(shí)候我們需要的是 "純粹" 的object
對象。 - 我們可以通過
Object.prototype.toString
方法準(zhǔn)確判斷某個對象值屬于哪種內(nèi)置類型御板。在介紹Object.prototype.toString
方法之前锥忿,我們先把toString()
方法和Object.prototype.toString.call()
方法進(jìn)行對比。
var arr=[1,2];
//直接對一個數(shù)組調(diào)用toString()
arr.toString();// "1,2"
//通過call指定arr數(shù)組調(diào)用Object.prototype對象上原始的toString方法
Object.prototype.toString.call(arr); //"[object Array]"
作為繼承的數(shù)組arr
重寫了toString
方法怠肋,并不是Object.prototype
中的toString
方法敬鬓。
- 為什么
toString
會有不同的作用呢?
其實(shí)笙各,這里面就涉及到js
原型及原型鏈的相關(guān)知識
var arr=[1,2,3];
Object.prototype.toString.call(arr); //"[object Array]"
Array.prototype.toString.call(arr); // "1,2,3"
arr.toString(); // "1,2,3"
看到這里大家都應(yīng)該明白了钉答,其實(shí)只有Object.prototype
上的toString
才能用來進(jìn)行復(fù)雜數(shù)據(jù)類型的判斷。
- 簡單解釋一些原型鏈的概念:
我們都知道js
中的對象都繼承自Object
杈抢,所以當(dāng)我們在某個對象上調(diào)用一個方法時(shí)数尿,會先在該對象上進(jìn)行查找,如果沒找到則會進(jìn)入對象的原型(也就是.prototype
)進(jìn)行查找惶楼,如果沒找到右蹦,同樣的也會進(jìn)入對象原型的原型進(jìn)行查找,直到找到或者進(jìn)入原型鏈的頂端Object.prototype
才會停止歼捐。
所以何陆,當(dāng)我們使用arr.toString()
時(shí),不能進(jìn)行復(fù)雜數(shù)據(jù)類型的判斷窥岩,因?yàn)樗{(diào)用的是Array.prototype.toString
。雖然Array
也繼承自Object
宰缤,但js
在Array.prototype
上重寫了toString
颂翼,而我們通過Object.prototype.toString.call(arr)
實(shí)際上是通過原型鏈調(diào)用了Object.prototype.toString
晃洒。
- 精確判斷對象的類型
JavaScript
中一切都是對象,任何都不例外朦乏,對所有值類型應(yīng)用Object.prototype.toString.call()
方法結(jié)果如下:
console.log(Object.prototype.toString.call(123)) //[object Number]
console.log(Object.prototype.toString.call('123')) //[object String]
console.log(Object.prototype.toString.call(undefined)) //[object Undefined]
console.log(Object.prototype.toString.call(true)) //[object Boolean]
console.log(Object.prototype.toString.call({})) //[object Object]
console.log(Object.prototype.toString.call([])) //[object Array]
console.log(Object.prototype.toString.call(function(){})) //[object Function]