Recursive/deep extend/assign in Underscore.js?

2019-01-08 00:28发布

Is there any way to get Underscore.js extend function:

Copy all of the properties in the source objects over to the destination object, and return the destination object. It's in-order, so the last source will override properties of the same name in previous arguments.

... to work recursively?

Actually, query property in creditOperation is going to completely override the query property defined in 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));

I'd like to obtain this creditOperation:

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

6条回答
三岁会撩人
2楼-- · 2019-01-08 01:00

Kurt Milam has published a mixin that adds a deepExtend method to underscore.js. It even deals with regular expressions (if you want). Excerpt from the documentation:

Mix it in with underscore.js: _.mixin({deepExtend: deepExtend});

Call it like this: var myObj = _.deepExtend(grandparent, child, grandchild, greatgrandchild)

Notes: Keep it DRY.

This function is especially useful if you're working with JSON config documents. It allows you to create a default config document with the most common settings, then override those settings for specific cases. It accepts any number of objects as arguments, giving you fine-grained control over your config document hierarchy.

查看更多
家丑人穷心不美
3楼-- · 2019-01-08 01:01

jQuery has an extend() function, which does the same thing as its Underscore counterpart, but also has a deep argument which allows it to merge recursively as you desire:

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

Or, if you don't want to overwrite baseOperation:

var creditOperation = $.extend(true, {}, baseOperation, {
    query: {
        'method': 'baz'
    }
});
查看更多
Deceive 欺骗
4楼-- · 2019-01-08 01:06

No, Underscore will not contain a deep extend since it's too complicated to deal with different types of objects. Instead, users are encouraged to implement their own solutions with the support for what they need.

In your case it's only plain objects, so an implementation is quite straightforward:

_.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;
}
查看更多
Explosion°爆炸
5楼-- · 2019-01-08 01:09

Stand-alone version of Bergi's deep extend, including the fix for when a value is a string instead of an object. Also patched to be more strict.

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;
}
查看更多
放我归山
6楼-- · 2019-01-08 01:13

With Lodash (fork of underscore) u can. Lodash's _.extend method accept third (or higher) parameter to be a function, that receives values (old and new); So u can do something like this:

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);

upd. As Paolo Moretti said in comments, there is the same function in lodash called _.merge:

_.merge(a,b);
查看更多
别忘想泡老子
7楼-- · 2019-01-08 01:21

underscore's extend() does not do deep extend; as a matter of fact, there is no function in underscore which can deep extend.

You may use lodash's merge for that.

查看更多
登录 后发表回答