Underscore.js 中的递归/深度扩展/分配?

IT技术 javascript underscore.js
2021-02-24 13:12:17

有什么办法可以得到 Underscore.jsextend函数:

将源对象中的所有属性复制到目标对象,并返回目标对象。它是有序的,因此最后一个源将覆盖先前参数中的同名属性。

...递归工作?

实际上,query属性 increditOperation将完全覆盖中query定义属性baseOperation

var url = require('url')
  , _ = require('underscore'),
  , baseOperation = {
        host: 'gateway.skebby.it',
        pathname: 'api/send/smseasy/advanced/http.php',
        protocol: 'https',
        query: {
            'username': 'foo',
            'password': 'bar',
        }
    };

var creditOperation = _.extend(baseOperation, {
    query: {
        'method': 'baz'
    }
});

console.log(url.format(creditOperation));

我想得到这个creditOperation

{
    host: 'gateway.skebby.it',
    pathname: 'api/send/smseasy/advanced/http.php',
    protocol: 'https',
    query: {
        'username': 'foo',
        'password': 'bar',
        'method': 'baz'
    }
}
6个回答

使用Lodash(下划线分叉)可以。Lodash 的_.extend方法接受第三个(或更高)参数作为一个函数,它接收值(旧的和新的);所以你可以做这样的事情:

var deep = function(a, b) {
    return _.isObject(a) && _.isObject(b) ? _.extend(a, b, deep) : b;
};

var a = {a:{b:{c:1}}},
    b = {a:{b:{z:1}}};

_.extend(a,b,deep);

更新。 正如Paolo Moretti在评论中所说,lodash 中有一个相同的函数叫做_.merge

_.merge(a,b);
这不能回答问题
2021-04-20 13:12:17
您还可以使用_.merge递归合并源对象的自己的可枚举属性,这些属性不会解析为未定义到目标对象中
2021-04-25 13:12:17
@wapsee,相反,我认为这是最有用的答案。
2021-04-27 13:12:17

jQuery 有一个extend()函数,它和 Underscore 对应的函数做同样的事情,但也有一个深度参数,允许它按照你的需要递归合并:

var creditOperation = $.extend(true, baseOperation, {
    query: {
        'method': 'baz'
    }
});

或者,如果您不想覆盖baseOperation

var creditOperation = $.extend(true, {}, baseOperation, {
    query: {
        'method': 'baz'
    }
});
谢谢你的这个,最好使用比自己写的好,反正项目中很多情况下都是用jquery的。
2021-05-08 13:12:17
第二个是百万美元的答案!!!我只能给你+1 :)
2021-05-09 13:12:17
这是许多人在找到此页面时真正想要的 :)
2021-05-17 13:12:17

Underscore 没有计划添加深度扩展,因为它被认为太复杂而无法处理不同类型的对象。相反,鼓励用户在他们需要的支持下实施他们自己的解决方案。

在您的情况下,它只是普通对象,因此实现非常简单:

_.deepObjectExtend = function(target, source) {
    for (var prop in source)
        if (prop in target)
            _.deepObjectExtend(target[prop], source[prop]);
        else
            target[prop] = source[prop];
    return target;
}
@wizzard:当然,extend我的个人库中有更复杂的功能变体——这里的这个并不是很通用。它只是处理来自 OP 想要混合的(深度嵌套的)属性的问题的用例。
2021-04-20 13:12:17
下划线不会,但它的替代品lodash有它,它的_.merge功能,参见。@Paolo_Moretti 评论:_.merge(target, source)
2021-05-16 13:12:17
当它遇到一个不是对象的属性时,这似乎会按原样抛出异常。在尝试递归之前,您需要验证 target[prop] 和 source[prop] 都是对象。也许类似于if (prop in target && typeof(target[prop]) == 'object' && typeof(source[prop]) == 'object')第三行。
2021-05-19 13:12:17
是的,我希望这个extend函数只能扩展(扩展?)对象,而不是覆盖其中的任何属性(说明普通对象)。如果你想要,if (typeof target[prop] == 'object')应该足够了。
2021-05-19 13:12:17
我不确定拥有两个具有相同属性的对象如何使它们不是普通对象。如果此函数处理具有相同属性的对象(以及更多本着 _.extend 的精神),则它的用处大约是 5 倍。此外,如果源道具不是对象而目标道具是:jsfiddle.net/wizzard/HY4yQ诚然,您可能想要如果您有这样的情况,请在此功能中多加考虑。
2021-05-20 13:12:17

Bergi 深度扩展的独立版本,包括修复值是字符串而不是对象时的问题。还修补了更严格。

function deepObjectExtend (target, source) {
    for (var prop in source) {
        if (source.hasOwnProperty(prop)) {
            if (target[prop] && typeof source[prop] === 'object') {
                deepObjectExtend(target[prop], source[prop]);
            }
            else {
                target[prop] = source[prop];
            }
        }
    }
    return target;
}

Kurt Milam 发布了一个mixin,deepExtend为 underscore.js添加了一个方法它甚至处理正则表达式(如果你愿意)。文档摘录:

将其与 underscore.js 混合: _.mixin({deepExtend: deepExtend});

像这样调用它: var myObj = _.deepExtend(grandparent, child, grandchild, greatgrandchild)

注意事项:保持干燥。

如果您正在处理 JSON 配置文档,则此功能特别有用。它允许您使用最常见的设置创建默认配置文档,然后针对特定情况覆盖这些设置。它接受任意数量的对象作为参数,让您可以对配置文档层次结构进行细粒度控制。