Как динамически объединить свойства двух объектов JavaScript?
Мне нужно иметь возможность объединить два (очень простых) объекта JavaScript во время выполнения. Например, я хотел бы:
var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog' }
obj1.merge(obj2);
//obj1 now has three properties: food, car, and animal
У кого-нибудь есть сценарий для этого или знаете встроенный способ сделать это? Мне не нужна рекурсия, и мне не нужно объединять функции, только методы на плоских объектах.
72 ответа
С Underscore.js, чтобы объединить массив объектов, сделайте:
var arrayOfObjects = [ {a:1}, {b:2, c:3}, {d:4} ];
_(arrayOfObjects).reduce(function(memo, o) { return _(memo).extend(o); });
Это приводит к:
Object {a: 1, b: 2, c: 3, d: 4}
Вы должны использовать lodash по умолчанию Deep
_.defaultsDeep({ 'user': { 'name': 'barney' } }, { 'user': { 'name': 'fred', 'age': 36 } });
// → { 'user': { 'name': 'barney', 'age': 36 } }
Стоит отметить, что версия из коллекции 140byt.es решает задачу в минимальном пространстве и стоит попробовать для этой цели:
Код:
function m(a,b,c){for(c in b)b.hasOwnProperty(c)&&((typeof a[c])[0]=='o'?m(a[c],b[c]):a[c]=b[c])}
Использование для ваших целей:
m(obj1,obj2);
Вот оригинальный Гист.
ES2018/TypeScript: Many answers are OK but I've come up with a more elegant solution to this problem when you need to merge two objects without overwriting overlapping object keys.
My function also accepts unlimited number of objects to merge as function arguments:
(I'm using TypeScript notation here, feel free to delete the :object[]
type in the function argument if you're using plain JavaScript).
const merge = (...objects: object[]) => {
return objects.reduce((prev, next) => {
Object.keys(prev).forEach(key => {
next[key] = { ...next[key], ...prev[key] }
})
return next
})
}
Вы можете использовать метод Object.assign.
Ex : obj1 = Object.assign(obj1,obj2);
он создает глубокую копию объекта json.
Используйте оператор Spread, который следует за версией ES6
var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog' }
let result = {...obj1,...obj2};
console.log(result)
output { food: 'pizza', car: 'ford', animal: 'dog' }
Я использую следующее в чистом JavaScript. Он начинается с самого правого аргумента и объединяет их вплоть до первого аргумента. Возвращаемого значения нет, изменен только первый аргумент, а самый левый параметр (кроме первого) имеет наибольший вес для свойств.
var merge = function() {
var il = arguments.length;
for (var i = il - 1; i > 0; --i) {
for (var key in arguments[i]) {
if (arguments[i].hasOwnProperty(key)) {
arguments[0][key] = arguments[i][key];
}
}
}
};
Использование:
//Takes any number of objects and returns one merged object
var objectMerge = function(){
var out = {};
if(!arguments.length)
return out;
for(var i=0; i<arguments.length; i++) {
for(var key in arguments[i]){
out[key] = arguments[i][key];
}
}
return out;
}
Это было проверено с:
console.log(objectMerge({a:1, b:2}, {a:2, c:4}));
Это приводит к:
{ a: 2, b: 2, c: 4 }
Мой метод:
function mergeObjects(defaults, settings) {
Object.keys(defaults).forEach(function(key_default) {
if (typeof settings[key_default] == "undefined") {
settings[key_default] = defaults[key_default];
} else if (isObject(defaults[key_default]) && isObject(settings[key_default])) {
mergeObjects(defaults[key_default], settings[key_default]);
}
});
function isObject(object) {
return Object.prototype.toString.call(object) === '[object Object]';
}
return settings;
}
:)
мелкий
var obj = { name : "Jacob" , address : ["America"] }
var obj2 = { name : "Shaun" , address : ["Honk Kong"] }
var merged = Object.assign({} , obj,obj2 ); //shallow merge
obj2.address[0] = "new city"
result.address[0] изменяется на "новый город", т.е. объединенный объект также изменяется. Это проблема неглубокого слияния.
глубокий
var obj = { name : "Jacob" , address : ["America"] }
var obj2 = { name : "Shaun" , address : ["Honk Kong"] }
var result = Object.assign({} , JSON.parse(JSON.stringify(obj)),JSON.parse(JSON.stringify(obj2)) )
obj2.address[0] = "new city"
result.address[0] не изменяется
function extend(o, o1, o2){
if( !(o instanceof Object) ) o = {};
copy(o, o1);
if( o2 )
copy(o, o2)
function isObject(obj) {
var type = Object.prototype.toString.call(obj);
return obj === Object(obj) && type != '[object Array]' && type != '[object Function]';
};
function copy(a,b){
// copy o2 to o
for( var key in b )
if( b.hasOwnProperty(key) ){
if( isObject(b[key]) ){
if( !isObject(a[key]) )
a[key] = Object.assign({}, b[key]);
else copy(a[key], b[key])
}
else
a[key] = b[key];
}
}
return o;
};
var o1 = {a:{foo:1}, b:1},
o2 = {a:{bar:2}, b:[1], c:()=>{}},
newMerged = extend({}, o1, o2);
console.log( newMerged )
console.log( o1 )
console.log( o2 )
Слияние JSON-совместимых объектов JavaScript
Я поощряю использование и использование неразрушающих методов, которые не изменяют исходный источник, "Object.assign" является деструктивным методом, а также оказывается, что он не так удобен для производства, потому что он перестает работать в более ранних браузерах, и у вас нет никакого способа исправляя это чисто, с альтернативой.
Объединение объектов JS всегда будет вне досягаемости или неполным, независимо от решения. Но объединение совместимых с JSON совместимых объектов находится всего в одном шаге от возможности написания простого и переносимого фрагмента кода неразрушающего метода объединения серии JS-объектов в возвращаемый мастер, содержащий все уникальные имена свойств и их соответствующие значения, синтезированные в единый главный объект по назначению.
Помнить, что MSIE8 является первым браузером, добавившим встроенную поддержку объекта JSON, - большое облегчение, и повторное использование уже существующей технологии всегда является желанной возможностью.
Ограничение вашего кода стандартными объектами JSON complant является большим преимуществом, чем ограничением, поскольку эти объекты также могут передаваться через Интернет. И, конечно же, для тех, кому нужна более глубокая обратная совместимость, всегда есть плагин json, методы которого можно легко назначить переменной JSON во внешнем коде без необходимости изменять или переписывать используемый метод.
function Merge( ){
var a = [].slice.call( arguments ), i = 0;
while( a[i] )a[i] = JSON.stringify( a[i++] ).slice( 1,-1 );
return JSON.parse( "{"+ a.join() +"}" );
}
(Конечно, всегда можно дать ему более осмысленное имя, которое я еще не определил; вероятно, следует назвать его JSONmerge)
Вариант использования:
var master = Merge( obj1, obj2, obj3, ...objn );
Теперь вопреки Object.assign
это оставляет все объекты нетронутыми и в их исходном состоянии (в случае, если вы сделали что-то не так и вам нужно изменить порядок объединенных объектов или иметь возможность использовать их отдельно для какой-либо другой операции, прежде чем объединять их снова).
Количество аргументов слияния также ограничено только лимитом длины аргументов [который огромен]. Собственно поддерживаемый синтаксический анализ / stringify JSON уже оптимизирован для машины, что означает: он должен быть быстрее любой скриптовой формы цикла JS. Итерация по заданным аргументам выполняется с использованием while
- оказался самым быстрым циклом в JS.
Коротко упомянуть тот факт, что мы уже знаем, что повторяющиеся свойства уникальных меток (ключей) объекта будут перезаписаны более поздним объектом, содержащим ту же метку ключа, что означает, что вы контролируете, какое свойство переходит во владение. предыдущий, просто упорядочив или переупорядочив список аргументов. И преимущество получения чистого и обновленного главного объекта без дубликатов в качестве конечного результата.
Расширение Госси метода Дэвида Колалье:
Проверьте эти две строки:
from = arguments[i];
Object.getOwnPropertyNames(from).forEach(function (name) {
Необходимо проверить "from" для нулевого объекта... Если, например, объединение объекта, полученного из ответа Ajax, ранее созданного на сервере, свойство объекта может иметь значение "null", и в этом случае выше Код генерирует ошибку, говоря:
"от" не является допустимым объектом
Так, например, перенос функции "...Object.getOwnPropertyNames(from).forEach..." на "if (from!= Null) { ... }" предотвратит возникновение этой ошибки.
С помощью следующего помощника вы можете объединить два объекта в один новый объект:
function extend(obj, src) {
for (var key in src) {
if (src.hasOwnProperty(key)) obj[key] = src[key];
}
return obj;
}
// example
var a = { foo: true }, b = { bar: false };
var c = extend(a, b);
console.log(c);
// { foo: true, bar: false }
Как правило, это полезно при объединении параметров с параметрами по умолчанию в функции или плагине.
Если поддержка IE 8 не требуется, вы можете использовать Object.keys
вместо этого для той же функциональности:
function extend(obj, src) {
Object.keys(src).forEach(function(key) { obj[key] = src[key]; });
return obj;
}
Это включает в себя немного меньше кода и немного быстрее.
объединить два объекта с помощью Object.assign и оператора распространения.
Неправильный способ (изменить исходный объект из-за ориентации на o1)
var o1 = { X: 10 };
var o2 = { Y: 20 };
var o3 = { Z: 30 };
var merge = Object.assign(o1, o2, o3);
console.log(merge) // {X:10, Y:20, Z:30}
console.log(o1) // {X:10, Y:20, Z:30}
Правильные пути
Object.assign({}, o1, o2, o3) ==> таргетинг на новый объект
{... o1,... o2,... o3} ==> разлетающиеся объекты
var o1 = { X: 10 };
var o2 = { Y: 20 };
var o3 = { Z: 30 };
console.log('Does not modify original objects because target {}');
var merge = Object.assign({}, o1, o2, o3);
console.log(merge); // { X: 10, Y: 20, Z: 30 }
console.log(o1)
console.log('Does not modify original objects')
var spreadMerge = {...o1, ...o2, ...o3};
console.log(spreadMerge);
console.log(o1);
ES5-совместимая нативная строка:
var merged = [obj1, obj2].reduce(function(a, o) { for(k in o) a[k] = o[k]; return a; }, {})
Есть разные способы добиться этого:
Object.assign(targetObj, sourceObj);
targetObj = {...targetObj, ...sourceObj};
Я использовал Object.create(), чтобы сохранить настройки по умолчанию (используя __proto__ или Object.getPrototypeOf()).
function myPlugin( settings ){
var defaults = {
"keyName": [ "string 1", "string 2" ]
}
var options = Object.create( defaults );
for (var key in settings) { options[key] = settings[key]; }
}
myPlugin( { "keyName": ["string 3", "string 4" ] } );
Таким образом, я всегда могу использовать concat () или push () позже.
var newArray = options['keyName'].concat( options.__proto__['keyName'] );
Примечание: вам нужно будет выполнить проверку hasOwnProperty перед объединением, чтобы избежать дублирования.
Вы можете объединить объекты, следуя моему методу
var obj1 = { food: 'pizza', car: 'ford' };
var obj2 = { animal: 'dog' };
var result = mergeObjects([obj1, obj2]);
console.log(result);
document.write("result: <pre>" + JSON.stringify(result, 0, 3) + "</pre>");
function mergeObjects(objectArray) {
if (objectArray.length) {
var b = "", i = -1;
while (objectArray[++i]) {
var str = JSON.stringify(objectArray[i]);
b += str.slice(1, str.length - 1);
if (objectArray[i + 1]) b += ",";
}
return JSON.parse("{" + b + "}");
}
return {};
}
В юи Y.merge
следует выполнить работу:
Y.merge(obj1, obj2, obj3....)
Правильная реализация в Prototype должна выглядеть так:
var obj1 = {food: 'pizza', car: 'ford'}
var obj2 = {animal: 'dog'}
obj1 = Object.extend(obj1, obj2);
Вот что я использовал в своей кодовой базе для слияния.
function merge(to, from) {
if (typeof to === 'object' && typeof from === 'object') {
for (var pro in from) {
if (from.hasOwnProperty(pro)) {
to[pro] = from[pro];
}
}
}
else{
throw "Merge function can apply only on object";
}
}
Это можно сделать тремя способами:
Подход 1: -
// using spread ...
let obj1 = {
...obj2
};
Подход 2:-
// using Object.assign() method
let obj1 = Object.assign({}, obj2);
Подход 3: -
// using JSON
let obj1 = JSON.parse(JSON.stringify(obj2));
Для тех, кто использует Node.js, есть модуль NPM: node.extend
Установка:
npm install node.extend
Использование:
var extend = require('node.extend');
var destObject = extend(true, {}, sourceObject);
// Where sourceObject is the object whose properties will be copied into another.
Я как бы начинаю с JavaScript, так что поправьте меня, если я ошибаюсь.
Но не лучше ли объединить любое количество объектов? Вот как я это делаю с помощью родного Arguments
объект.
Ключом к этому является то, что вы можете фактически передать любое количество аргументов функции JavaScript, не определяя их в объявлении функции. Вы просто не можете получить к ним доступ, не используя объект Arguments.
function mergeObjects() (
var tmpObj = {};
for(var o in arguments) {
for(var m in arguments[o]) {
tmpObj[m] = arguments[o][m];
}
}
return tmpObj;
}
Возможный способ добиться этого заключается в следующем.
if (!Object.prototype.merge){
Object.prototype.merge = function(obj){
var self = this;
Object.keys(obj).forEach(function(key){
self[key] = obj[key]
});
}
};
Я не знаю, лучше ли это, чем другие ответы. В этом методе вы добавляете merge function
в Objects
прототип. Таким образом, вы можете позвонить obj1.merge(obj2);
Примечание: вы должны проверить свой аргумент, чтобы увидеть, является ли он объектом, и "бросить" правильный Error
, Если не Object.keys
выдаст "ошибку"
Мы можем создать пустой объект и объединить их for-loop
:
var obj1 = {
id: '1',
name: 'name'
}
var obj2 = {
c: 'c',
d: 'd'
}
var obj3 = {}
for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; }
for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; }
console.log( obj1, obj2, obj3)
Это сливается obj
в "по умолчанию" def
, obj
имеет приоритет для всего, что существует в обоих, так как obj
копируется в def
, Обратите внимание, что это рекурсивно.
function mergeObjs(def, obj) {
if (typeof obj == 'undefined') {
return def;
} else if (typeof def == 'undefined') {
return obj;
}
for (var i in obj) {
if (obj[i] != null && obj[i].constructor == Object) {
def[i] = mergeObjs(def[i], obj[i]);
} else {
def[i] = obj[i];
}
}
return def;
}
a = {x : {y : [123]}}
b = {x : {z : 123}}
console.log(mergeObjs(a, b));
// {x: {y : [123], z : 123}}