寻找一个函数来执行比underscore.js扩展函数更复杂的工作

时间:2014-03-01 11:26:59

标签: javascript underscore.js

我想知道是否有一些helper JavaScript库的函数类似于underscore.js的_.extend。 我正在寻找的是一个给出如下关联数组的函数:

{ foo: 1, bar: 2 }

和另一个“扩展”关联数组,如下所示:

{ foo : 3 }

可以轻松构建以下“增强”结构:

{ foo: [1, 3], bar: 2 }

否则我必须手动完成,但这个任务似乎足以成为某个帮助程序库中的函数。

澄清了一个关于不同对象应该发生什么的例子:

基础对象:{ foo: 1, bar: 2 }

扩展对象:{ quuz: 3, bar: 4 }

结果:{ foo: 1, bar: [2, 4], quuz: 3 }

实际上,现在我很清楚操作是可交换的(基础和扩展可以切换,结果总是相同的)

其他示例:

基础对象:{ foo: 1, bar: [2,5] }

扩展对象:{ foo: {a: 'A', b: 'B'} , bar: 4 }

结果:{ foo: [1, {a: 'A', b: 'B'}], bar: [2, 4, 5], quuz: 3 }

2 个答案:

答案 0 :(得分:2)

您的要求不是很清楚,您希望在不同的对象中发生什么?但是,这是一个浅薄的扩展,它可以完成您的要求,或者将其用作实验的基础并将其调整到您的设计中。

的Javascript

function curstomExtend(target) {
    var typeTarget = typeof target;

    if (target === null || typeTarget !== 'object' && typeTarget !== 'function') {
        throw new TypeError('target');
    }

    Array.prototype.slice.call(arguments, 1).forEach(function (source) {
        var typeSource = typeof source;

        if (source === null || typeSource !== 'object' && typeSource !== 'function') {
            throw new TypeError('source');
        }

        Object.keys(source).forEach(function (key) {
            var temp;

            if (target.hasOwnProperty(key)) {
                if (Array.isArray(target[key])) {
                    target[key].push(source[key]);
                } else {
                    target[key] = [target[key]];
                    target[key].push(source[key]);
                }
            } else {
                target[key] = source[key];
            }
        });
    });

    return target;
};

var a = {
    foo: 1,
    bar: 2,
    fy: {
        a: 1,
        b: 2
    }
},
b = {
    foo: 3,
    fy: {
        s: 3,
        t: 4
    }
},
c = {
    foo: [4, 5]
},
d = {
    foo: {
        x: 4,
        y: 5
    },
    fy: {
        s: 5,
        t: 6
    }
};

curstomExtend(a, b, c, d);

console.log(JSON.stringify(a));

输出

{"foo":[1,3,[4,5],{"x":4,"y":5}],"bar":2,"fy":[{"a":1,"b":2},{"s":3,"t":4},{"s":5,"t":6}]} 

jsFiddle

答案 1 :(得分:0)

我的解决方案

我写了以下函数blendblend_many,结合起来, 能够以递归方式“混合”两个对象。

/**
 * applies blend to all the objects contained in the input list.
 * The output is an object that contains a blend of all the input objects.
 */

function blend_many(list) {
    var ret = _.reduce(list, blend, {});
    for (var key in ret) {
        var value = ret[key];

        if (_.isArray(value)) {
            var all_are_objects = _.reduce(value, function (a, b) {
                return a && _.isObject(b);
            }, true);
            if (all_are_objects) {
                // recurse!
                value = blend_many(value);
            }
        }
        ret[key] = value;
    }
    return ret;
}

function blend(base, extending) {
    for (key in extending) {
        var value = extending[key];

        if (_.isArray(value)) {
            // recurse
            value = blend_many(value);
        }

        if (base[key] === undefined) {
            base[key] = value;
        } else if (_.isArray(base[key])) {
            base[key].push(value)
        } else {
            var prev = base[key];
            base[key] = [prev, value];
        }
    }
    return base;
}

例如,呼叫:

list_of_objs = [
  {
    a: {
      foo: 1
    }
  },
  {
    a: {
      foo: 2
    }
  }
];
blend_many(list_of_objs);

将返回以下对象:

{
  a: {
    foo: [ 1, 2 ]
  }
}

(对于构建mongodb查询非常有用!)