mapObject

underscore虽然把map功能从数组扩展到了集合上,但是即使是对象,最终结果也是数组的形式,mapObject方法类似于map方法,只是最终结果以对象的形式呈现:

_.mapObject = function(obj, iteratee, context) {
    iteratee = cb(iteratee, context);
    var keys =  _.keys(obj),
        length = keys.length,
        results = {},
        currentKey;
    for (var index = 0; index < length; index++) {
        currentKey = keys[index];
        results[currentKey] = iteratee(obj[currentKey], currentKey, obj);
    }
    return results;
};

这和实现和map的实现对比一下,除了map方法为了兼容数组和对象相关的代码,可以说是几乎一模一样。

functions

functions方法的作用是获取一个对象所有方法名,想实现这个功能也不难,遍历判断属性值是否是函数即可:

_.functions = _.methods = function(obj) {
    var names = [];
    // 不仅仅是自身的方法,原型链上的方法也考虑进来了
    for (var key in obj) {
        if (_.isFunction(obj[key])) names.push(key);
    }
    return names.sort();
};

pick omit

pick方法的作用是返回一个新对象,新对象所具有的属性根据传入的参数决定。它有两种模式,第一种是传入一个判断函数,根据这个函数的返回值决定新对象是否有这个属性,第二种是传入一组属性,新对象的属性由这一组属性决定。

_.pick = function(object, oiteratee, context) {
    var result = {}, obj = object, iteratee, keys;
    if (obj == null) return result;
    // 传入判断函数
    if (_.isFunction(oiteratee)) {
        // 迭代的属性范围是全部属性,包括原型链上的属性
        keys = _.allKeys(obj);
        iteratee = optimizeCb(oiteratee, context);
    } else {
    // 传入属性模式
        keys = flatten(arguments, false, false, 1);
        // 该模式下仅需判断原始对象是否有对应属性
        iteratee = function(value, key, obj) { return key in obj; };
        obj = Object(obj);
    }
    for (var i = 0, length = keys.length; i < length; i++) {
        var key = keys[i];
        var value = obj[key];
        if (iteratee(value, key, obj)) result[key] = value;
    }
    return result;
};

omit方法是pick方法的取反,类似于reject和filter方法的关系,omit方法也利用了pick方法:

_.omit = function(obj, iteratee, context) {
    // 传入判断函数模式,将传入函数包装成取反的函数
    if (_.isFunction(iteratee)) {
        iteratee = _.negate(iteratee);
    } else {
        // 传入属性模式,将其包装成传入判断函数模式
        var keys = _.map(flatten(arguments, false, false, 1), String);
        iteratee = function(value, key) {
            return !_.contains(keys, key);
        };
    }
    return _.pick(obj, iteratee, context);
};

has

underscore的has方法几乎可以认为是原生的hasOwnProperty方法的别名:

var hasOwnProperty = ObjProto.hasOwnProperty;
_.has = function(obj, key) {
    return obj != null && hasOwnProperty.call(obj, key);
};

对于一般的对象,has和直接使用hasOwnProperty没有区别,但是对于使用Object.create(null)创建出来的新对象,由于其原型链上没有hasOwnProperty方法,所以直接使用hasOwnProperty会出问题。

property propertyOf

property方法我最开始提高阶函数的时候就说过了,它传入一个key,返回一个新函数,新函数的功能是返回传入对象的key属性的值。

propertyOf方法有点不知所云了,它是传入一个对象obj,返回一个新函数,新函数的功能是传入key返回对象key属性的值。正常情况下和直接获取对象的属性没什么区别,大概是考虑对象obj为非法值时的容错吧。

var property = function(key) {
    return function(obj) {
        return obj == null ? void 0 : obj[key];
    };
};
_.property = property;

_.propertyOf = function(obj) {
    return obj == null ? function(){} : function(key) {
        return obj[key];
    };
};

results matching ""

    No results matching ""