參考文章:資料型別
typeof 運算子
JavaScript
有三種方法,可以確定一個值到底是什麼型別。
- typeof運算子
- instanceof運算子
- Object.prototype.toString方法
typeof
typeof
運算子可以返回一個值的資料型別。
- 數值、字串、布林值分別返回
number
、string
、boolean
。
typeof 123 // "number"
typeof '123' // "string"
typeof false // "boolean"
複製程式碼
- 函式返回
function
。
function f() {}
typeof f
// "function"
複製程式碼
undefined
返回undefined
。
typeof undefined
// "undefined"
複製程式碼
利用這一點,typeof
可以用來檢查一個沒有宣告的變數,而不報錯。
v
// ReferenceError: v is not defined
typeof v
// "undefined"
複製程式碼
上面程式碼中,變數v
沒有用var
命令宣告,直接使用就會報錯。但是,放在typeof
後面,就不報錯了,而是返回undefined
。
實際程式設計中,這個特點通常用在判斷語句。
// 錯誤的寫法
if (v) {
// ...
}
// ReferenceError: v is not defined
// 正確的寫法
if (typeof v === "undefined") {
// ...
}
複製程式碼
- 物件返回
object
。
typeof window // "object"
typeof {} // "object"
typeof [] // "object"
複製程式碼
typeof
缺點:上面程式碼中,空陣列([])的型別也是object
,這表示在 JavaScript
內部,陣列本質上只是一種特殊的物件。 typeof
無法區分陣列和物件。
這裡順便提一下,instanceof
運算子可以區分陣列和物件。
var o = {};
var a = [];
o instanceof Array // false
a instanceof Array // true
複製程式碼
- null返回object。因為
null
被認為是一個空的物件的引用。
typeof null // "object"
複製程式碼
instanceof
instanceof
運算子返回一個布林值,表示物件是否為某個建構函式的例項。
- 下面程式碼中,物件
v
是建構函式Vehicle
的例項,所以返回true
。
var v = new Vehicle();
v instanceof Vehicle // true
複製程式碼
instanceof
運算子的左邊是例項物件,右邊是建構函式。instanceof
的作用:會檢查右邊建構函式的原型物件(prototype
),是否在左邊物件的原型鏈上。因此,下面兩種寫法是等價的。
v instanceof Vehicle
// 等同於
Vehicle.prototype.isPrototypeOf(v)
複製程式碼
上面程式碼中,Object.prototype.isPrototypeOf
的含義如下:
var p = {x:1};//定義一個原型物件
var o = Object.create(p);//使用這個原型建立一個物件
p.isPrototypeOf(o);//=>true:o繼承p
Object.prototype.isPrototypeOf(p);//=> true p繼承自Object.prototype
複製程式碼
- 由於
instanceof
檢查整個原型鏈,因此同一個例項物件,可能會對多個建構函式都返回true
。
var d = new Date();
d instanceof Date // true
d instanceof Object // true
複製程式碼
上面程式碼中,d
同時是Date
和Object
的例項,因此對這兩個建構函式都返回true
。
instanceof
的原理是檢查右邊建構函式的prototype
屬性,是否在左邊物件的原型鏈上。有一種特殊情況,就是左邊物件的原型鏈上,只有null
物件。這時,instanceof
判斷會失真。
var obj = Object.create(null);
typeof obj // "object"
Object.create(null) instanceof Object // false
複製程式碼
上面程式碼中,Object.create(null)
返回一個新物件obj
,它的原型是null
(Object.create的詳細介紹見後文)。右邊的建構函式Object
的prototype
屬性,不在左邊的原型鏈上,因此instanceof
就認為obj
不是Object
的例項。但是,只要一個物件的原型不是null
,instanceof
運算子的判斷就不會失真。
instanceof
運算子的一個用處,是判斷值的型別。
var x = [1, 2, 3];
var y = {};
x instanceof Array // true
y instanceof Object // true
複製程式碼
上面程式碼中,instanceof
運算子判斷,變數x
是陣列,變數y
是物件。
缺點:instanceof
運算子只能用於物件(純物件和陣列),不適用原始型別(Undefined、Null、Boolean、Number 和 String)的值。
var s = 'hello';
s instanceof String // false
複製程式碼
上面程式碼中,字串不是String
物件的例項(因為字串不是物件),所以返回false
。
此外,對於undefined
和null
,instanceOf
運算子總是返回false
。
undefined instanceof Object // false
null instanceof Object // false
複製程式碼
- 利用
instanceof
運算子,還可以巧妙地解決,呼叫建構函式時,忘了加new
命令的問題。
function Fubar (foo, bar) {
if (this instanceof Fubar) {
this._foo = foo;
this._bar = bar;
} else {
return new Fubar(foo, bar);
}
}
複製程式碼
上面程式碼使用instanceof
運算子,在函式體內部判斷this
關鍵字是否為建構函式Fubar
的例項。如果不是,就表明忘了加new
命令。
Object.prototype.toString
- 要想區別物件、陣列、函式單純使用
typeof
是不行的。null
和Array
的結果也是object
,有時候我們需要的是 "純粹" 的object
物件。 - 我們可以通過
Object.prototype.toString
方法準確判斷某個物件值屬於哪種內建型別。在介紹Object.prototype.toString
方法之前,我們先把toString()
方法和Object.prototype.toString.call()
方法進行對比。
var arr=[1,2];
//直接對一個陣列呼叫toString()
arr.toString();// "1,2"
//通過call指定arr陣列呼叫Object.prototype物件上原始的toString方法
Object.prototype.toString.call(arr); //"[object Array]"
複製程式碼
作為繼承的陣列arr
重寫了toString
方法,並不是Object.prototype
中的toString
方法。
- 為什麼
toString
會有不同的作用呢? 其實,這裡面就涉及到js
原型及原型鏈的相關知識
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"
複製程式碼
看到這裡大家都應該明白了,其實只有Object.prototype
上的toString
才能用來進行復雜資料型別的判斷。
- 簡單解釋一些原型鏈的概念:
我們都知道js
中的物件都繼承自Object
,所以當我們在某個物件上呼叫一個方法時,會先在該物件上進行查詢,如果沒找到則會進入物件的原型(也就是.prototype
)進行查詢,如果沒找到,同樣的也會進入物件原型的原型進行查詢,直到找到或者進入原型鏈的頂端Object.prototype
才會停止。
所以,當我們使用arr.toString()
時,不能進行復雜資料型別的判斷,因為它呼叫的是Array.prototype.toString
。雖然Array
也繼承自Object
,但js
在Array.prototype
上重寫了toString
,而我們通過Object.prototype.toString.call(arr)
實際上是通過原型鏈呼叫了Object.prototype.toString
。
- 精確判斷物件的型別
JavaScript
中一切都是物件,任何都不例外,對所有值型別應用Object.prototype.toString.call()
方法結果如下:
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]
複製程式碼