1. 程式人生 > 其它 >js:typeof與instanceof區別

js:typeof與instanceof區別

typeof


typeof運算子返回一個用來表示表示式的資料型別的字串。

返回值為6個字串,分別為stringBooleannumberfunctionobjectundefined

  let  a = [1,2,3],
        b = 1,
        c = 'test',
        d = function(){console.log('test function')},
        e = true,
        f = null,
        g;

console.log(typeof(a));     //object
console.log(typeof
(b)); //number console.log(typeof(c)); //string console.log(typeof(d)); //function console.log(typeof(e)); //boolean console.log(typeof(f)); //object console.log(typeof(g)); //undefined

typeof的侷限性: typeof在判斷nullarrayobject以及函式例項(new + 函式)時,得到的都是object,這使得在判斷這些資料型別的時候,得不到真是的資料型別。

instanceof


instanceof用來檢測某個物件是不是另一個物件的例項。

官方的話:該運算髮用來測試一個物件在其原型鏈中是否存在一個建構函式prototype屬性

instance中文翻譯為例項,用來判斷該物件是誰的例項,同時我們也就知道instanceof是物件運算子。

這裡的例項就牽扯到了物件的繼承,它的判斷就是根據原型鏈進行搜尋,在物件obj1的原型鏈上如果存在另一個物件obj2的原型屬性,那麼表示式(obj1 instanceof obj2)返回值為true;否則返回false。
var a = new Array();

console.log(a instanceof Array);    //
會返回 true console.log(a instanceof Object); // 也會返回 true 因為Array是object 的子類 -------------------------------------------------------------- function Foo(){} Foo.prototype = new Aoo(); // 原型繼承 var foo = new Foo(); console.log(foo instanceof Foo) //true console.log(foo instanceof Aoo) //true instanceof不僅可以判斷一層繼承關係,也可以判斷多層繼承關係 -------------------------------------------------------------- var a = new Array(); if(a instanceof Object) // 返回true if(window instanceof Object) // 返回false typeof(window) //會得到object 需要注意的是,如果表示式 obj instanceof Foo 返回true,則並不意味著該表示式會永遠返回ture,因為Foo.prototype屬性的值有可能會改變,改變之後的值很有可能不存在於obj的原型鏈上,這時原表示式的值就會成為false

總結:


typeof和instanceof都是用來判斷變數型別的,兩者的區別在於:

  • typeof判斷所有變數的型別,返回值有number,boolean,string,function,object,undefined。
  • typeof對於豐富的物件例項,只能返回"Object"字串。
  • instanceof用來判斷物件,程式碼形式為obj1 instanceof obj2(obj1是否是obj2的例項),obj2必須為物件,否則會報錯!其返回值為布林值。
  • instanceof可以對不同的物件例項進行判斷,判斷方法是根據物件的原型鏈依次向下查詢,如果obj2的原型屬性存在obj1的原型鏈上,(obj1 instanceof obj2)值為true。

補充:


使用 Object.prototype.tostring.call(obj) 檢測物件型別

先看使用示例

console.log(Object.prototype.toString.call("jerry"));//[object String]
console.log(Object.prototype.toString.call(12));//[object Number]
console.log(Object.prototype.toString.call(true));//[object Boolean]
console.log(Object.prototype.toString.call(undefined));//[object Undefined]
console.log(Object.prototype.toString.call(null));//[object Null]
console.log(Object.prototype.toString.call({name: "jerry"}));//[object Object]
console.log(Object.prototype.toString.call(function(){}));//[object Function]
console.log(Object.prototype.toString.call([]));//[object Array]
console.log(Object.prototype.toString.call(new Date));//[object Date]
console.log(Object.prototype.toString.call(/\d/));//[object RegExp]
function Person(){};
console.log(Object.prototype.toString.call(new Person));//[object Object]

為什麼這樣就能區分呢?於是我去看了一下toString方法的用法:toString方法返回反映這個物件的字串。

那為什麼不直接用obj.toString()呢?

console.log("jerry".toString());//jerry
console.log((1).toString());//1
console.log([1,2].toString());//1,2
console.log(new Date().toString());//Wed Dec 21 2016 20:35:48 GMT+0800 (中國標準時間)
console.log(function(){}.toString());//function (){}
console.log(null.toString());//error
console.log(undefined.toString());//error

同樣是檢測物件obj呼叫toString方法,obj.toString()的結果和Object.prototype.toString.call(obj)的結果不一樣,這是為什麼?

這是因為toString為Object的原型方法,而Array、Function等型別作為Object的例項,都重寫了toString方法。不同的物件型別呼叫toString方法時,根據原型鏈的知識,呼叫的是對應的重寫之後的toString方法(Function型別返回內容為函式體的字串,Array型別返回元素組成的字串.....),而不會去呼叫Object上原型toString方法(返回物件的具體型別),所以採用obj.toString()不能得到其物件型別,只能將obj轉換為字串型別;因此,在想要得到物件的具體型別時,應該呼叫Object上原型toString方法。

我們可以驗證一下,將陣列的toString方法刪除,看看會是什麼結果:

var arr=[1,2,3];
console.log(Array.prototype.hasOwnProperty("toString"));//true
console.log(arr.toString());//1,2,3
delete Array.prototype.toString;//delete操作符可以刪除例項屬性
console.log(Array.prototype.hasOwnProperty("toString"));//false
console.log(arr.toString());//"[object Array]"

刪除了Array的toString方法後,同樣再採用arr.toString()方法呼叫時,不再有遮蔽Object原型方法的例項方法,因此沿著原型鏈,arr最後呼叫了Object的toString方法,返回了和Object.prototype.toString.call(arr)相同的結果。