javascript 合并两个对象而不覆盖
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20590177/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Merge two objects without override
提问by amp
I have a defaultObject like that:
我有一个这样的 defaultObject:
var default = {
abc: "123",
def: "456",
ghi: {
jkl: "789",
mno: "012"
}
};
And I have another like:
我还有另一个喜欢:
var values = {
abc: "zzz",
ghi: {
jkl: "yyy",
}
};
How can I merge those 2 objects with the following result (no override)?
如何将这 2 个对象与以下结果合并(无覆盖)?
var values = {
abc: "zzz",
def: "456",
ghi: {
jkl: "yyy",
mno: "012"
}
};
(I don't want to change the default object!)
(我不想更改默认对象!)
采纳答案by adeneo
With ES2015 now being supported in all modern browsers, the native Object.assign
can be used to extend objects
现在所有现代浏览器都支持 ES2015,本机Object.assign
可用于扩展对象
Object.assign({}, _default, values)
Note that default
is a reserved keyword, and can't be used as a variable name
注意这default
是一个保留关键字,不能用作变量名
The original answer, written in 2013 :
原始答案,写于 2013 年:
Since this is tagged with jQuery, you could use $.extendfor a simple cross-browser solution
由于这是用 jQuery 标记的,因此您可以使用$.extend作为简单的跨浏览器解决方案
var temp = {};
$.extend(true, temp, _default, values);
values = temp;
回答by Oriol
For those who don't use jQuery, here comes a vanilla-js solution.
对于那些不使用 jQuery 的人,这里有一个 vanilla-js 解决方案。
Solution:
解决方案:
function extend (target) {
for(var i=1; i<arguments.length; ++i) {
var from = arguments[i];
if(typeof from !== 'object') continue;
for(var j in from) {
if(from.hasOwnProperty(j)) {
target[j] = typeof from[j]==='object'
? extend({}, target[j], from[j])
: from[j];
}
}
}
return target;
}
Compressed(with Closure Compiler):
压缩(使用Closure Compiler):
Only 199 characters!
只有 199 个字符!
var extend=function e(c){for(var d=1;d<arguments.length;++d){var a=arguments[d];if("object"===typeof a)for(var b in a)a.hasOwnProperty(b)&&(c[b]="object"===typeof a[b]?e({},c[b],a[b]):a[b])}return c}
How to use:
如何使用:
extend(target, obj1, obj2); // returns target
If you only want to merge, use
如果您只想合并,请使用
var merged = extend({}, obj1, obj2);
Features:
特点:
- It doesn't look at objects' prototype.
- Ignores non-objects.
- It is recursive in order to merge properties which are objects.
- Objects referenced in
target
's properties, if extended, are replaced by new ones, and the original ones are not modified. - In case of same property names, the merged value will be the merging of the objects after the last (in the order of arguments) non-object value. Or, if the last isn't an object, itself.
- 它不看对象的原型。
- 忽略非对象。
- 为了合并作为对象的属性,它是递归的。
target
的属性中引用的对象,如果被扩展,会被新的替换,并且不会修改原始的。- 在相同属性名称的情况下,合并值将是最后一个(按参数顺序)非对象值之后的对象的合并。或者,如果最后一个不是对象,则是它本身。
Examples:
例子:
extend({}, {a:1}, {a:2}); // {a:2}
extend({}, {a:1}, {b:2}); // {a:1, b:2}
extend({}, {a: {b:1}}, {a: {b:2}}); // {a: {b:2}}
extend({}, {a: {b:1}}, {a: {c:2}}); // {a: {b:2, c:2}}
extend({}, {a: {a:1}}, {a: {b:2}}, {a: 'whatever non object'});
// {a: "whatever non object"}
extend({}, {a: {a:1}}, {a: {b:2}}, {a: 'whatever non object'}, {a: {c:3}},{a: {d:4}});
// {a: {c:3, d:4}}
Warning:
警告:
Be aware that if browser is not clever enough, it could be trapped in an infinite loop:
请注意,如果浏览器不够聪明,它可能会陷入无限循环:
var obj1={},
obj2={};
obj1.me=obj1;
obj2.me=obj2;
extend({},obj1,obj2);
If the browser is clever enough, it can throw an error, or return {me: undefined}
, or whatever.
如果浏览器足够聪明,它可以抛出一个错误,或者 return {me: undefined}
,或者其他什么。
Note that this warning also applies if you use jQuery's $.extend
.
请注意,如果您使用 jQuery 的$.extend
.
回答by typingduck
Also if you are happy with ES6:
另外,如果您对 ES6 感到满意:
Object.assign({}, default, values)
回答by Bowen Yang
Another way would be to simply extend value by default (instead of the other way around which would override default)
另一种方法是简单地默认扩展值(而不是覆盖默认值的另一种方式)
Object.assign(value, default) // values of default overrides value
default = value // reset default to value
The caveat here is that the content of value is changed as well. Upside is no library is required and easier than the plain vanilla solution above.
这里的警告是 value 的内容也发生了变化。好处是不需要库,并且比上面的普通解决方案更容易。
回答by mbaer3000
My version based on Oriol's answer adds a check for arrays, so that arrays don't get transformed into funny {'0': ..., '1': ...} thingys
我基于 Oriol 的回答的版本添加了对数组的检查,这样数组就不会变成有趣的 {'0': ..., '1': ...} thingys
function extend (target) {
for(var i=1; i<arguments.length; ++i) {
var from = arguments[i];
if(typeof from !== 'object') continue;
for(var j in from) {
if(from.hasOwnProperty(j)) {
target[j] = typeof from[j]==='object' && !Array.isArray(from[j])
? extend({}, target[j], from[j])
: from[j];
}
}
}
return target;
}
回答by Henric Malmberg
I found that the easiest way to to this is to use mergeWith()
from lodash ( https://lodash.com/docs/4.17.15#mergeWith) which accepts a customizer function that decides what to do with every property merge. Here is one that is recursive :
我发现最简单的方法是使用mergeWith()
from lodash ( https://lodash.com/docs/4.17.15#mergeWith),它接受一个定制器函数,该函数决定如何处理每个属性合并。这是一个递归的:
const mergeFunction = (objValue, srcValue) => {
if (typeof srcValue === 'object') {
_.mergeWith(objValue, srcValue, mergeFunction)
} else if (objValue) {
return objValue
} else {
return srcValue
}
}