JavaScript中的型別判斷,瞭解一下?

descire發表於2018-05-23

在前端專案中,誰還沒有被物件型別錯誤坑過?

typeof操作符

通過typeof操作符獲取運算元的型別:

  typeof undefined; // undefined
  typeof []; // object
  typeof '123'; // string
複製程式碼

關於typeof操作符,我們需要記住兩點,第一點:當運算元為null時。

  typeof null; // object
複製程式碼

第二點:當運算元為原始型別(Primitive)時很有效,但是對於物件具體型別的判斷往往並不是我們需要的結果。

Tip: 6大原始型別Null、Undefined、String、Number、Boolean和Symbol。

  typeof '123'; // string
  typeof new String('123'); // object
複製程式碼

Tip: 剛開始學習JS時,常聽說:“JS中萬物皆物件”,實際上這裡的萬物並不包含這裡的Primitive Value。

instanceof操作符

instanceof操作符主要用來檢查建構函式的原型是否在物件的原型鏈上。

  const s = new String('123');

  s instanceof String; // true
  s instanceof Object; // true
複製程式碼

接下來讓我們搞點事情:

  s.__proto__ = Object.prototype;

  s instanceof String; // false
  s instanceof Object; // true
複製程式碼

利用instanceof操作符,我們可以對自定義的物件進行判斷:

  function Animal (name) {
    this.name = name
  }

  const fizz = new Animal('fizz');

  fizz instanceof Animal // true
複製程式碼

constructor屬性

實際上我們也可以通過constructor屬性來達到型別判斷的效果:

  fizz.constructor === Animal // true
複製程式碼

但是在實際情況下,constructor屬性可以被隨意修改,而且你在原型繼承中,很容易忽略掉constructor的正確指向:

  function Rabbit (name) {
    Animal.call(this, name)
  }

  Rabbit.prototype = Object.create(Animal.prototype);
  // 需要手動設定constructor的正確指向
  Rabbit.prototype.constructor = Rabbit;

  const rabbit = new Rabbit('?');

  rabbit.constructor === Rabbit // true
複製程式碼

從好的程式設計習慣來說,我們應該要保持constructor屬性的正確指向。

toString方法

利用toString方法基本上可以解決所有內建物件型別的判斷:

  function type (obj) {
    return Reflect.apply(Object.prototype.toString, obj, []).replace(/^\[object\s(\w+)\]$/, '$1').toLowerCase()
  }
  
  type(new String('123')) // string
複製程式碼

但是這種方法對於自定義的建構函式仍然無效。

內建Symbol介面

ES6中通過Symbol暴露了一些內建的API:

  Animal.prototype[Symbol.toStringTag] = 'Animal';
  type(rabbit) // animal
複製程式碼

現在,我們可以通過toString滿足所有的需求了,但是也不乏有很皮的程式設計師:

  const o = {
    get [Symbol.toStringTag] () {
      return 'Array'
    }
  }

  type(o) // array
複製程式碼

例外對於instanceof操作符也暴露了Symbol.hasInstance,這裡就不再贅述了。

那些年的坑

這裡就舉一個簡單的例子:

  function test (decimal) {
    if (type(decimal) === 'number') {
      return decimal.toFixed(2)
    } else if (type(decimal) === 'string') {
      return parseFloat(decimal).toFixed(2)
    } else {
      return '0.00'
    }
  }

  test(28.39843) // 28.40
  test('323.2321321') // 323.23
複製程式碼

用過toFixed()方法的人都知道它是Number.prototype上的方法,如果傳入的並不是數字型別,那就會出現各種問題。

當然我們處於一個前端工具蓬勃發展的時代,湧現了很多靜態型別檢查的工具:


    喜歡本文的小夥伴們,歡迎關注我的訂閱號超愛敲程式碼,檢視更多內容.

JavaScript中的型別判斷,瞭解一下?

相關文章