underscore.js 源碼解讀:常用類型判斷以及一些有用的工具方法

Why underscore

最近開始看 underscore.js 源碼,並將 underscore.js 源碼解讀 放在了我的 2016 計劃中。

閱讀一些著名框架類庫的源碼,就好像和一個個大師對話,你會學到很多。爲什麼是 underscore?最主要的原因是 underscore 簡短精悍(約 1.5k 行),封裝了 100 多個有用的方法,耦合度低,非常適合逐個方法閱讀,適合樓主這樣的 JavaScript 初學者。從中,你不僅可以學到用 void 0 代替 undefined 避免 undefined 被重寫等一些小技巧 ,也可以學到變量類型判斷、函數節流&函數去抖等常用的方法,還可以學到很多瀏覽器兼容的 hack,更可以學到作者的整體設計思路以及 API 設計的原理(向後兼容)。

之後樓主會寫一系列的文章跟大家分享在源碼閱讀中學習到的知識。

歡迎圍觀~ (如果有興趣,歡迎 star & watch~)您的關注是樓主繼續寫作的動力

類型判斷

第一篇跟大家簡單地聊了下爲什麼 underscore.js 用 void 0 代替了 undefined,意外地收到了不錯的反響,有朋友私信我說以前還真不知道這回事,也有人催促我趕緊繼續下一篇解讀文章。今天就跟大家聊一聊 underscore.js 中一些 JavaScript 常用類型檢查方法,以及一些工具類的判斷方法。

我們先說個老生常談的問題,JavaScript 中數組類型的判斷方法,事實上,我在 Javascript中判斷數組的正確姿勢 一文中已經詳細分析了各種判斷方式的優缺點,並給出了正確的判斷代碼:


function isArray(a) {

  Array.isArray ? Array.isArray(a) : Object.prototype.toString.call(a) === '[object Array]';

}

而 underscore 其實也正是這麼做的:


// Is a given value an array?

// Delegates to ECMA5's native Array.isArray

// 判斷是否爲數組

_.isArray = nativeIsArray || function(obj) {

  return toString.call(obj) === '[object Array]';

};

nativeIsArray 正是 ES5 中 Array.isArray 方法,如果支持則優先調用;而 toString 變量就保存了 Object.prototype.toString。

如何判斷對象?underscore 把類型爲 function 和 object 的變量都算作對象,當然得除去 null。


// Is a given variable an object?

// 判斷是否爲對象

// 這裏的對象包括 function 和 object

_.isObject = function(obj) {

  var type = typeof obj;

  return type === 'function' || type === 'object' & !!obj;

};

再看 ‘Arguments’, ‘Function’, ‘String’, ‘Number’, ‘Date’, ‘RegExp’, ‘Error’ 這些類型的判斷,其實都可以用 Object.prototype.toString.call 來判斷,所以寫在了一起:


// Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError.

// 其他類型判斷

_.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function(name) {

  _['is' + name] = function(obj) {

    return toString.call(obj) === '[object ' + name + ']';

  };

});

但是看 isArguments 方法,在 IE


// Define a fallback version of the method in browsers (ahem, IE

// there isn't any inspectable "Arguments" type.

// _.isArguments 方法在 IE

// IE

// 結果是 [object Object]

// 而並非我們期望的 [object Arguments]。

// so 用是否含有 callee 屬性來判斷

if (!_.isArguments(arguments)) {

  _.isArguments = function(obj) {

    return _.has(obj, 'callee');

  };

}

工具類判斷方法

接下來看下一些常用的工具類判斷方法。

判斷一個元素是否是 DOM 元素,非常簡單,只需要保證它不爲空,且 nodeType 屬性爲 1:


// Is a given value a DOM element?

// 判斷是否爲 DOM 元素

_.isElement = function(obj) {

  // 確保 obj 不是 null

  // 並且 obj.nodeType === 1

  return !!(obj & obj.nodeType === 1);

};

如何判斷一個元素爲 NaN?NaN 其實是屬於 Number 類型,Object.prototype.toString.call(NaN) 返回的是 “[object Number]”,而且 NaN 不等於本身,利用這兩點即可進行判斷:


// Is the given value `NaN`? (NaN is the only number which does not equal itself).

// 判斷是否是 NaN

// NaN 是唯一的一個 `自己不等於自己` 的 number 類型

_.isNaN = function(obj) {

  return _.isNumber(obj) & obj !== +obj;

};

當然,underscore 還有很多其他的有用的工具類判斷方法,具體可以看源碼 https://github.com/hanzichi/underscore-analysis/blob/master/underscore-1.8.3.js/src/underscore-1.8.3.js#L1192-L1263 這部分。

如果您覺得我分享的東西對您有所幫助,請關注我的 Repo https://github.com/hanzichi/underscore-analysis

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章