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'
}
}
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;
}
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);
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'
}
});
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;
}
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.
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.