Javascript 中的數據類型判斷

本系列經過閱讀 underscore 源碼與實戰進而體驗函數式編程的思想, 而非經過冗長的文字教程, 細讀精度
約 1500 行的 underscore 有利於寫出耦合度低, 符合函數式編程思想的代碼, 而且能夠學到 call 與 apply 執行效率的不一樣進而進行代碼性能優化的技巧等.javascript

歡迎你們 star 或者 watch 本系列, 您的關注是做者的最大動力, 讓咱們一塊兒持續進步.
本系列倉庫: github.com/zhangxiang9…html

Typeof

咱們都使用 typeof 是用來判斷數據類型的命令, 在常規的場景中足以應付數據類型判斷的需求:java

var obj = {
   name: 'zhangxiang'
};

function foo() {
    console.log('this is a function');
}

var arr = [1,2,3];

console.log(typeof 1);  // number
console.log(typeof '1');  //string
console.log(typeof true);  //boolean
console.log(typeof null); //object
console.log(typeof undefined); //undefined
console.log(typeof obj); //object
console.log(typeof foo);  //function
console.log(typeof arr);   //object複製代碼

能夠看到, typeof 命令能夠判斷全部 javascript 中的基本數據類型(Null, Undefined, Boolean, String, Number), 雖然 null 使用 typeof 返回的是 object 字符串, 可是無礙
它的基本使用, 可是在一些複雜的場景好比 object 與 null, array 與 object, function 與 object 等等的類型區分, typeof 就會顯得心有餘力不足了.
因此通常來講, typeof 會使用在比較簡單的場景, 好比你幾乎能夠肯定數據是哪一類數據而後稍微加以區分的時候.舉個簡單的例子來講明狀況:node

function unique(array){
  var hash = {};
  var result = [], key;
  array.forEach(function(item, index){
    key = item;
    if(typeof item === 'string') {
      key = '_' + item;
    }
    if(!hash[key]) {
      result.push(item);
    } else {
      hash[key] = true;
    }
  });
  return result;
}複製代碼

instanceof

instanceof 其實適合用於判斷自定義的類實例對象, 而不是用來判斷原生的數據類型, 舉個例子:git

// a.html
<script>
  var a = [1,2,3];
</script>複製代碼
//main.html
<iframe src="a.html"></iframe>

<script>
  var frame = window.frame[0];
  var a = frame.a;
  console.log(a instanceof Array);  // false
  console.log(a.contructor === Array);  //false
  console.log(a instanceof frame.Array); // true
</script>複製代碼

是什麼緣由致使上面的結果呢? 其實 iframe 之間不會共享原型鏈, 由於他們有獨立的執行環境, 因此 frame a 中的數組 a 不會是本執行環境的實例對象. 經過特性嗅探一樣不靠譜, 像經過 contructor
sort, slice 等等的特有的數組(或者其餘數據類型)方法或屬性, 萬一對象中也有 sort, slice 屬性, 就會發生誤判. 因此最靠譜的方法是使用 Object.prototype.toString 方法.github

Object.prototype.toString

使用 Object.prototype.toString 方法, 能夠獲取到變量的準確的類型.編程

function foo(){};

Object.prototype.toString.call(1);  '[object Number]'
Object.prototype.toString.call('1'); '[object String]'
Object.prototype.toString.call(NaN); '[object Number]'
Object.prototype.toString.call(foo);  '[object Function]'
Object.prototype.toString.call([1,2,3]); '[object Array]'
Object.prototype.toString.call(undefined); '[object Undefined]'
Object.prototype.toString.call(null); '[object Null]'
Object.prototype.toString.call(true); '[object Boolean]'
....複製代碼

Object.prototype.toString 的原理是當調用的時候, 就取值內部的 [[Class]] 屬性值, 而後拼接成 '[object ' + [[Class]] + ']' 這樣的字符串並返回. 而後咱們使用 call 方法來獲取任何值的數據類型.數組

有用的數據類型判斷函數

isArray polyfill

isArray 是數組類型內置的數據類型判斷函數, 可是會有兼容性問題, 因此模擬 underscore 中的寫法以下:瀏覽器

isArray = Array.isArray || function(array){
  return Object.prototype.toString.call(array) === '[object Array]';
}複製代碼

isNaN polyfill

判斷一個數是否是 NaN 不能單純地使用 === 這樣來判斷, 由於 NaN 不與任何數相等, 包括自身, 因此:性能優化

isNaN: function(value){
  return isNumber(value) && isNaN(value);
}複製代碼

這裏的 isNumber 就是用上面所說的 Object.prototype.toString 進行判斷的, 而後使用 isNaN 來判斷值, 至於爲何須要在判斷 isNaN 以前須要判斷是否是 Number 類型, 這是由於 NaN 自己
也是數字類型(Object.prototype.toString 可知), 在 ES6 的 isNaN 中只有值爲數字類型使用 NaN 纔會返回 true, 這是爲了模擬 ES6 的 isNaN.

判斷是不是 DOM 元素

在實際項目裏面, 有時或許咱們須要判斷是不是 DOM 元素對象, 那麼在判斷的時候利用的是 DOM 對象特有的 nodeType 屬性:

isElement: function(obj){
  return !!(obj && obj.nodeType === 1);
}複製代碼

判斷是不是對象

isObject: function(obj){
  var type = typeof obj;
  return type === 'function' || typeof === 'object' && obj !== null;
}複製代碼

這裏的對象是狹義的, 是一般所指的 key-value 型的集合, 或者是 function 函數而且不爲 null.

判斷是不是 arguments 對象 polyfill

判斷一個對象是否是 arguments 對象能夠經過 Object.prototype.toString 來判斷, 可是低版本的瀏覽器不支持, 他們返回的是 [object Object], 因此須要兼容:

isArguments: function(obj){
  return Object.prototype.toString.call(obj) === '[object Arguments]' || (obj != null && Object.hasOwnProperty.call(obj, 'callee'));
}複製代碼

兼容作法原理是經過對象的 hasOwnProperty 方法來判斷對象是否擁有 callee 屬性從而判斷是否是 arguments 對象.

若是以爲有收穫, 請到 github 給做者一個 star 表示支持吧, 謝謝你們.
本系列倉庫: github.com/zhangxiang9…

相關文章
相關標籤/搜索