談談前端JavaScript 型別判斷typeof和instanceof的區別及一個型別判斷Util的簡單實現
instanceof和typeof運算子都能用來判斷一個變數是否為空或是什麼型別。typeof用以獲取一個變數的型別,typeof一般只能返回如下幾個結果果:number, boolean, string, function, object, undefined。我們可以使用typeof來獲取一個變數是否存在,如if(typeof a!=“undefined”){//TODO},對於Date, Array, Null等特殊物件使用typeof一律返回object,這正是typeof的侷限性。instanceof用於判斷一個變數是否某個物件的例項,如var a=new Array(); alert(a instanceof Array);會返回true,同時alert(a instanceof Object)也會返回true;這是因為Array是object的子類。
1、typeof運算子
typeof是一元運算子,放在運算元前面,返回表示運算元型別的一個字串。任意運算元在typeof運算後返回值如下:
運算元 x | typeof x | example |
---|---|---|
undefined | “undefined” | var a; typeof a; //undefiend |
null | “object” | var a = null; typeof a; //object |
true | “boolean” | var a = true; typeof a; //boolean |
數字或NaN | “number” | var a = “12” - 0; typeof a; //number |
任意字串 | “string” | var a = 12 + “”; typeof a; //string |
任意函式 | “function” | var a = function(){}; function b(){}; typeof a; typeof b;//function function |
任意內建物件 | “object” | var a = new Date, b = new Array(1); typeof a; type b; //object object |
通過上表我們可以看出typeof返回4類值:
- 原始值:string, number, boolean
- undefined
- function
- object:Date, Array等
注意function其實是object的一種,但是typeof返回function而不是object,需要注意,原因可以簡單理解為:function是可執行的,根據ECMAScript3規範,對於所有內建可執行物件,typeof運算子一律返回"function"。
typeof運算對於判斷運算元是原始值型別還是物件型別,尤其判斷變數是否定義過非常有用,但是對於判斷具體是Date還是Array還是其它就無能為力啦,需要instanceof運算子或其它技術手段實現。
2、instanceof運算子
instanceof運算子希望左運算元是一個物件,右運算元標識物件型別的類。如果左側物件是右側類的例項,則返回true,否則返回false。通俗點理解就是:instanceof判斷一個物件是否為某一資料型別,或一個變數是否為一個物件的例項。看個案例:
var d = new Date;
d instanceof Date; //true
d instanceof Object; //true, 所有物件都是object的例項
d instanceof Number; //false
var a = [1,2,3];
a instanceof Array; //true
a instanceof Object; //true, 所有陣列都是物件
a instanceof RegExp; //false
instanceof工作機制基於JavaScript原型鏈,類似Java繼承關係。為了計算表示式o instanceof f,首先計算f.prototype,然後在o的原型鏈中查詢f.prototype,如果找到,那麼o是f的一個例項,表示式返回true。如果f.prototype不在o的原型鏈中,那麼o就不是f的一個例項,表示式返回false。
判斷:o.proto.proto…會不會等於f.prototype, 看個案例:
function C(){}
function D(){}
var o = new C();
console.log('o instanceof C: ', o instanceof C); // true, o.__proto__ == C.prototype
console.log('o instanceof D: ', o instanceof D); // false, D.prototype不在o的原型鏈上
console.log('o instanceof Object: ', o instanceof Object); // true, o.__proto__.__proto__ == Object.prototype
console.log(C.prototype instanceof Object) // true, C.prototype.__proto__ = Object.prototype
C.prototype = {};
var o2 = new C();
console.log(o2 instanceof C); // true
console.log("o instanceof C", o instanceof C); //false, C.prototype指向了一個空物件,這個物件不在o的原型鏈上.
D.prototype = new C();
var o3 = new D();
o3 instanceof D; // true,
o3 instanceof C; // true, o3是D的例項,而D繼承C
3、型別判斷TypeUtil的簡單實現
我們可以通過Object.prototype.toString方法,判斷某個物件值屬於哪種內建型別,一個案例:
var TypeUtil = (function() {
return {
isString: function(str) {
return Object.prototype.toString.call(str) === "[object String]";
},
isNumber: function(num) {
return Object.prototype.toString.call(num) === "[object Number]";
},
isBoolean: function(flag) {
return Object.prototype.toString.call(flag) === "[object Boolean]";
},
isFunc: function(fn) {
return Object.prototype.toString.call(fn) === "[object Function]";
},
isArray: function(arr) {
return Object.prototype.toString.call(arr) === "[object Array]";
},
isObject: function(obj) {
return Object.prototype.toString.call(obj) === "[object Object]";
}
};
}());
console.log("TypeUtil.isString: ", TypeUtil.isString("1212")); //true
console.log("TypeUtil.isNumber: ", TypeUtil.isNumber(1212)); //true
console.log("TypeUtil.isBoolean: ", TypeUtil.isBoolean(true)); //true