首先看一些在object塊定義的常用的類型判斷函數。
_.isElement(object)
_.isElement = function(obj) {
return !!(obj && obj.nodeType === 1);
};
nodeType相關知識點:
| 節點類型 | 描述 | 名稱 | |
|---|---|---|---|
| 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 |
其實一般來説是會隱式轉換的...可能這裏是在強制轉換避免出錯吧。
_.isArray(object)
_.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來判斷:
Array.isArray([]) // true
但是依然存在一種調用object的toString()方法來判斷的辦法:
Object.prototype.toString.call([]) // "[object Array]"
這個辦法還可以用來判斷別的各種類型:
_.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function(name) {
_['is' + name] = function(obj) {
return toString.call(obj) === '[object ' + name + ']';
};
});
_.each方法之後會細説,當做原生的forEach來看吶。
_.isObject(value)
_.isObject = function(obj) {
var type = typeof obj;
return type === 'function' || type === 'object' && !obj;
};
嗯...這裏要注意的是運算符的優先級,&&優先級高於||,所以這裏把函數也作為object來看待了...
_.isObject(function f() {}) // true
_.isArguments(object)
if (!_.isArguments(arguments)) {
_.isArguments = function(obj) {
return _.has(obj, 'callee');
};
}
因為IE<9下對arguments調用Object.prototype.toString.call(),返回的是[object Object],而非[object Arguments],所以遇到這種情況需要判斷一下是否還有callee屬性。
_.isFunction(object)
if (typeof /./ != 'function' && typeof Int8Array != 'object') {
_.isFunction = function(obj) {
return typeof obj === 'function' || false;
};
}
Safari5及之前版本、Chrome7及之前版本在對正則表達式調用typeof操作符時會返回function,所以就是為了功能兼容吧。
_.isFinite(object)
_.isFinite = function(obj) {
return isFinite(obj) && !isNaN(parseFloat(obj));
};
用到了JavaScript的全局函數isFinite,會檢查參數是否為無窮大。
isFinite(function f() {}) // false,因為值為NaN
isFinite(123) // true
_.isNaN(object)
_.isNaN = function(obj) {
return _.isNumber(obj) && obj !== +obj;
};
首先判斷是否為數字,其次判斷其本身是否與自己相等。
嗯,這是隻針對數字的判斷。
還有這樣一個bug...???
_.isBoolean(object)
_.isBoolean = function(obj) {
return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
};
其實我感覺可能直接用toString.call(obj) === '[object Boolean]'就可以...
_.isNull(object)和_.isUndefined(value)
_.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(object)
_.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;
};
判斷是否為空的方法:
- 如果是null,則為空;
- 如果是有長度的結構(數組,類數組,字符串等),則判斷其長度;
- 如果是object,則判斷由
key組成的數組的長度~
_.has(obj, key)
_.has = function(obj, key) {
return obj != null && hasOwnProperty.call(obj, key);
};
首先要確定傳入的對象不能為空,然後用hasOwnProperty來檢查是否為對象的屬性。