Native way to merge objects in Javascript
Javascript's Object doesn't have any native merge operation. If you have two objects, say
{a:1, b:2}
{c:3, d:4}
And want to get
{a:1, b:2, c:3, d:4}
As far as I know, you have to iterate through the objects. That is to say that you decide on either a merge left or merge right strategy and then you do something like (simplified)
for (key in object2) {
object1[key] = object2[key];
}
This is fine. However, Javascript has the call
and prototype
feature. For instance, turning arguments
into an Array
can be done with
Array.prototype.slice.call(arguments)
This approach exploits existing native code, and so therefore is less susceptible to programmer folly and should run faster than a non-native implementation.
The question
Is there a trick to use this prototype/call pattern on perhaps the Attribute
or Node
traversal features of the DOM, or perhaps some of the generic String
functions in order to do a native object merge?
The code would look something like this:
var merged = somethingrandom.obscuremethod.call(object1, object2)
And as a result, you'd get a native merge without a traversal.
A possible, sub-optimal solution
If you could use the constructor
property of an Object
and then coerce one object to have a constructor of another object and then run new
over the composite object, you may get a merge for free. But I don't have a firm grasp of the full implications of the constructor
feature in javascript to make this call.
Lemma
The same question holds true for Arrays
. A common problem is to take, say 7 arrays of numbers, then try to find out the intersection of those arrays. That is to say, which numbers exist in all 7 arrays.
You could concat them together, then do a sort, and then do a traversal, surely. But it would be nice if there is a generic intersect tucked away somewhere that we can coerce an array to doing natively.
Any thoughts?
edit:
Getting half way there
For the array problem, you could do the following:
array.concat(a, b, c).sort().join(':') and then use some tricky RegExp
capture and repeat patterns in order to traverse. RegExp implementations, if you don't know, run on a very simple stack-based virtual machine. When you initialize your regular expression that's really a program that gets compiled (RegExp.compile is a deprecated JS method). Then the native runs over the string in a blisteringly fast way. Perhaps you could exploit that for membership thresholds and get better performance...
It still doesn't go all the way though.
My answer to this will be disappointing, but still:
no
The reason for this is simple: Mr Resig's implementation of merge (or "extend" as it's called for objects) in jQuery is doing a loop, just like the one in your question. You can look at it here. And I dare say that if John Resig hasn't found a clever build-in way to do it, then the mere mortals of stackoverflow won't either :)
The million dollar question! I've tried doing this numerous ways, and the loop way described above always seemed the dirtiest. ES6's Object.setPrototypeOf()
allows you to delegate a "property override" object to a "default properties" object, pretty much accomplishing what you're trying to do, but using Object.setPrototypeOf()
has some serious implications, like disabling the browser's compiler optimizations for the whole script.
Also, in both the loop solution and the Object.setPrototypeOf()
solution, you are left with a situation where the "property override" object can mutate the "default properties" object:
defaultObj = {
a: [1, 2]
}
...
overrideObj = {
b: 3
}
Object.setPrototypeOf(overrideObj, defaultObj);
console.log(overrideObj); // {a: [1, 2], b: 3}
// Great!
...
overrideObj.a.push(4);
console.log(defaultObj); // {a: [1, 2, 4]}
// Uh-oh.
You might think this is not a problem, but let's say you're using this object as configuration for a 3rd party lib. You are now handing the control of your default object and everything referenced in it to the 3rd party lib.
A better solution might be to use JSON.stringify and JSON.parse to copy and combine the objects. Here's a Gist with the example: https://gist.github.com/spikesagal/6f7822466887f19b9c65
HTH
Not that I know of, no. Also, you'll want to write your merge method like this:
function mergeInto(o1, o2) {
if (o1 == null || o2 == null)
return o1;
for (var key in o2)
if (o2.hasOwnProperty(key))
o1[key] = o2[key];
return o1;
}
链接地址: http://www.djcxy.com/p/94018.html