Как динамически объединить свойства двух объектов JavaScript? - PullRequest
2173 голосов
/ 05 октября 2008

Мне нужно иметь возможность объединять два (очень простых) объекта JavaScript во время выполнения. Например, я хотел бы:

var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog' }

obj1.merge(obj2);

//obj1 now has three properties: food, car, and animal

Кто-нибудь имеет сценарий для этого или знает встроенный способ сделать это? Мне не нужна рекурсия, и мне не нужно объединять функции, только методы для плоских объектов.

Ответы [ 60 ]

3 голосов
/ 22 апреля 2015

Я использую следующее в чистом 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];
      }
    }
  }
};
2 голосов
/ 14 марта 2019

ES2018 / TypeScript: многие ответы в порядке, но я предложил более элегантное решение этой проблемы, когда вам нужно объединить два объекта без перезаписи перекрывающихся клавиш объекта .

Моя функция также принимает неограниченное количество объектов для объединения в качестве аргументов функции:

(здесь я использую нотацию TypeScript, не стесняйтесь удалять тип :object[] в аргументе функции, если вы используете простой JavaScript).

const merge = (...objects: object[]) => {
  return objects.reduce((prev, next) => {
    Object.keys(prev).forEach(key => {
      next[key] = { ...next[key], ...prev[key] }
    })
    return next
  })
}
2 голосов
/ 24 августа 2011

расширение Госси метода Дэвида Колалье:

Проверьте эти две строки:

from = arguments[i];
Object.getOwnPropertyNames(from).forEach(function (name) {

Необходимо проверить "from" для нулевого объекта ... Если, например, объединение объекта, полученного из ответа Ajax , ранее созданного на сервере, свойство объекта может иметь значение " null ", и в этом случае приведенный выше код генерирует ошибку, говорящую:

"from" не является допустимым объектом

Так, например, перенос функции «... Object.getOwnPropertyNames (from) .forEach ...» на «if (from! = Null) {...}» предотвратит возникновение этой ошибки.

2 голосов
/ 01 ноября 2011

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 )
2 голосов
/ 09 июля 2011

Использование:

//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 }
2 голосов
/ 01 августа 2013

Мой путь:

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

:)

1 голос
/ 09 апреля 2014

Для тех, кто использует 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.
1 голос
/ 11 января 2016

Вот что я использовал в своей кодовой базе для слияния.

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 голос
/ 01 июля 2011

Я как бы начинаю с 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;
}
1 голос
/ 24 апреля 2017

ES5-совместимая нативная строка:

var merged = [obj1, obj2].reduce(function(a, o) { for(k in o) a[k] = o[k]; return a; }, {})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...