首先看一些在object塊定義的經常使用的類型判斷函數。node
_.isElement = function(obj) { return !!(obj && obj.nodeType === 1); };
nodeType相關知識點:git
節點類型 | 描述 | 名稱 | |
---|---|---|---|
1 | Element | 元素 | ELEMENT_NODE |
2 | Attr | 屬性 | ATTRIBUTE_NODE |
3 | Text | 文本內容 | TEXT_NODE |
8 | Comment | 註釋 | COMMENT_NODE |
9 | Document | 整個文檔(DOM)樹的根節點 | DOCUMENT_NODE |
11 | DocumentFragment | 某個文檔片斷 | DOCUMENT_FRAGMENT_NODE |
其實通常來講是會隱式轉換的...可能這裏是在強制轉換避免出錯吧。github
_.isArray = nativeIsArray || function(obj) { return toString.call(obj) === '[object Array]'; };
吶吶...underscore的開頭就引用了js原生的一些方法:正則表達式
var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; var push = ArrayProto.push, slice = ArrayProto.slice, toString = ObjProto.toString, hasOwnProperty = ObjProto.hasOwnProperty; var nativeIsArray = Array.isArray, nativeKeys = Object.keys, nativeBind = FuncProto.bind, nativeCreate = Object.create;
而關於[object Array]
...數組
當判斷一個對象是否爲數組時,不能用typeof
運算符進行操做,由於會返回object
:函數
typeof([]) // "object"
那這個時候怎麼判斷數組是否是數組呢...雖然如今有原生的isArray
來判斷:spa
Array.isArray([]) // true
可是依然存在一種調用object的toString()
方法來判斷的辦法:prototype
Object.prototype.toString.call([]) // "[object Array]"
這個辦法還能夠用來判斷別的各類類型:code
_.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function(name) { _['is' + name] = function(obj) { return toString.call(obj) === '[object ' + name + ']'; }; });
_.each
方法以後會細說,當作原生的forEach
來看吶。對象
_.isObject = function(obj) { var type = typeof obj; return type === 'function' || type === 'object' && !obj; };
嗯...這裏要注意的是運算符的優先級,&&優先級高於||,因此這裏把函數也做爲object來看待了...
_.isObject(function f() {}) // true
if (!_.isArguments(arguments)) { _.isArguments = function(obj) { return _.has(obj, 'callee'); }; }
由於IE<9下對arguments調用Object.prototype.toString.call()
,返回的是[object Object]
,而非[object Arguments]
,因此遇到這種狀況須要判斷一下是否還有callee屬性。
if (typeof /./ != 'function' && typeof Int8Array != 'object') { _.isFunction = function(obj) { return typeof obj === 'function' || false; }; }
Safari5及以前版本、Chrome7及以前版本在對正則表達式調用typeof
操做符時會返回function
,因此就是爲了功能兼容吧。
_.isFinite = function(obj) { return isFinite(obj) && !isNaN(parseFloat(obj)); };
用到了JavaScript的全局函數isFinite
,會檢查參數是否爲無窮大。
isFinite(function f() {}) // false,由於值爲NaN isFinite(123) // true
_.isNaN = function(obj) { return _.isNumber(obj) && obj !== +obj; };
首先判斷是否爲數字,其次判斷其自己是否與本身相等。
嗯,這是隻針對數字的判斷。
還有這樣一個bug...???
_.isBoolean = function(obj) { return obj === true || obj === false || toString.call(obj) === '[object Boolean]'; };
其實我感受可能直接用toString.call(obj) === '[object Boolean]'
就能夠...
_.isNull = function(obj) { return obj === null; }; _.isUndefined = function(obj) { return obj === void 0; };
這裏就涉及到了爲何用void 0
而不是undefined
,
在非嚴格模式下,咱們能夠爲全局標識符
undefined
賦值--《你不知道的js》
可是我沒運行出來。並且嚴格模式下也沒有報錯...
function foo() { undefined = 2 } console.log(undefined) // undefined
能夠聲明一個名爲undefined
的局部變量卻是真的。
function foo() { var undefined = 2 console.log(undefined) // 2 } foo()
因此說明使用undefined
不少時候是不靠譜的。
那void 0
呢,表達式void
沒有返回值,所以返回結果是undefined
,void
並不改變表達式的結果,只是讓表達式不返回值。在這個層面上講,void 0
,void a
都是同樣的。
var obj = {a: 3} void obj // undefined
_.isEmpty = function(obj) { if (obj === null) return true; if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0; return _.keys(obj).length === 0; };
判斷是否爲空的方法:
key
組成的數組的長度~_.has = function(obj, key) { return obj != null && hasOwnProperty.call(obj, key); };
首先要肯定傳入的對象不能爲空,而後用hasOwnProperty
來檢查是否爲對象的屬性。