博客 / 詳情

返回

underscore源碼解讀系列之一--underscore的一些工具函數

首先看一些在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沒有返回值,因此返回結果是undefinedvoid並不改變表達式的結果,只是讓表達式不返回值。在這個層面上講,void 0void 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來檢查是否為對象的屬性。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.