首先看一些在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来检查是否为对象的属性。


oneday
279 声望4 粉丝

引用和评论

0 条评论