1. 程式人生 > >js中typeof和instanceof詳解

js中typeof和instanceof詳解

類陣列物件和物件

文章開始先來看一下js中陣列物件和類陣列物件。在js中陣列是一個物件,陣列物件繼承自Array物件

   var arr1 = [];
   var arr2 = new Array();

這兩種方式定義出來的陣列,由於Array.prototype上有大量的方法,因此陣列物件可以使用多種方法。那麼既然陣列是一個物件,那麼我們自然會想到用一個普通的物件來模擬陣列物件,於是就出現了類陣列物件

   var likeArray = {
      0: 'zero',
      1: 'one',
      2: 'two',
      length: 3,
      otherMethod: function
(){
alert('otherMethod!'); } }

這樣構造出來的物件,使用數字字串作為key值,還有一個length屬性來記錄物件中元素個數,也可以掛載其他方法,這樣的物件就叫做類陣列物件。類陣列物件既可以用數字進行索引,也可以用for迴圈進行遍歷,還有可以使用call轉化成陣列物件,這裡不明白的可以參考我另外一篇文章call和apply上手分析
那麼js有幾種基本型別,String,Number , 布林型別,Null,undefined。其中String型別同時也是類陣列物件,類陣列物件我們更關注它的使用,而不關心它的型別。

typeof和instanceof

接下來進入我們的主題,先看typeof的語法

   typeof operand

typeof將返回operand的型別

   typeof 0   // return 'number'
   typeof '0'   //return 'string',字元串同時也是一個類陣列物件
   typeof false  // return 'boolean'
   function fn(){ }
   typeof fn   // return 'function'
   var param;
   typeof param   // return 'undefined'
   //ES6 新加入的型別
typeof Symbol() // 'symbol'

typeof在判斷基本型別的時候非常給力,但在判斷物件時就力不從心,上文說到陣列是一個有很多方法的強大物件,那麼

   typeof [1, 2, 3]  // return 'object'
   typeof null   // return 'object'
   typeof {x: 1}  // return 'object'

typeof不能區分出陣列,null和普通物件,那麼instanceof解決了這個問題,下面看instanceof

   A instanceof B

instanceof用來檢查A的原型鏈上是否存在B的原型,或者直接一點說,B在不在A的原型鏈上,關於原型鏈繼承可以參考我的另一篇文章原型繼承及其應用

   function A(){ }
   function B(){ }
   var a = new A();
   a instanceof A();   // return true
   a instanceof B();   // return false;

   function Parent(){ }
   function Child(){ }
   Child.prototype = new Parent();
   var grandChild = new Child();
   grandChild instanceof Parent  //return true

可以看到,只要B存在於A的原型鏈上就返回true, 那麼

   [1, 2, 3] instanceof Array  //return true
   null instanceof Object  // return false
   var obj = {}
   obj instanceof Object   // return true

這樣就可以區分陣列,null和普通物件,然而在一些基本型別的判斷上

   5 instanceof Number  // return false
   var num = new Number('5')
   num instanceof Number // return true
   '' instanceof String  // return false

只有通過new出來的基本型別才能通過instanceof判斷,所以,在判斷是否字串,是否數字,是否布林值的時候,我們應該使用typeof。而對陣列和要判斷物件是否是在某個建構函式或物件的原型鏈上時使用instanceof,對函式的判斷兩者皆可。
我們還可以證明字串是一個類陣列物件

   var a = '';
   var str = new String('test');
   str instanceof Object  //return true
   str instanceof String  // return true
   a instanceof String // return false
   a instanceof Object // return false 

通過建構函式new出來的字串通過了檢測,雖然字面直接量a沒有,但是使用中推薦直接使用字面直接量。

if判斷

再聊一聊if判斷

   var a = ...
   if(a){
      //do something
   }

實際上就是

   var a = ...
   if(typeof a !== 'undefined' && a !== 0 && a !== null && a !== false){
       // do something
   }

我們注意到,對這四個值typeof,只有null會返回 object。所以當我們想判斷一個物件是否為null的時候,需要用複合條件

   if(!obj && typeof obj === 'object')

當我們想判斷一個物件是否是null或undefined的時候,可以使用

   // 只有null和undefined會返回true
   if(obj == null)

當我們在if判斷中使用未定義的變數時,就會報錯。

   if(b){ ... }  // b is not defined...

在除錯模式中,DEBUG變數的宣告只有在開發和測試時才會被載入到瀏覽器,在生產環境中不予載入,這時我們要怎麼檢測DEBUG變數是否宣告呢,安全的方法是使用typeof

   if(typeof DEBUG !== 'undefined'){
      console.log('debug is beginning')
   }

當if判斷中的變數是某個物件的屬性時

   var obj = {
      data: {
         num: 5
      }
   }
   //不推薦
   if(obj.data.num){
      obj.data.num ...
   }
   //推薦
   var a = obj.data.num;
   if(a){
       ...
   }   

在取物件屬性層級巢狀的時候,先儲存在變數中,既可以避免重複取屬性消耗效能,又可以避免出錯,在使用if判斷以及typeof和instanceof的時候,要注意這一點