Как динамически объединить свойства двух объектов 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 ]

2456 голосов
/ 05 октября 2008

Стандартный метод ECMAScript 2018

Вы бы использовали объект распространения :

let merged = {...obj1, ...obj2};

/** There's no limit to the number of objects you can merge.
 *  Later properties overwrite earlier properties with the same name. */
const allRules = {...obj1, ...obj2, ...obj3};

ECMAScript 2015 (ES6) Стандартный метод

/* For the case in question, you would do: */
Object.assign(obj1, obj2);

/** There's no limit to the number of objects you can merge.
 *  All objects get merged into the first object. 
 *  Only the object in the first argument is mutated and returned.
 *  Later properties overwrite earlier properties with the same name. */
const allRules = Object.assign({}, obj1, obj2, obj3, etc);

(см. Справочник MDN JavaScript )


Метод для ES5 и ранее

for (var attrname in obj2) { obj1[attrname] = obj2[attrname]; }

Обратите внимание, что это просто добавит все атрибуты obj2 к obj1, которые могут не соответствовать вашим требованиям, если вы все еще хотите использовать неизмененный obj1.

Если вы используете фреймворк, охватывающий все ваши прототипы, вам придется потрудиться с проверками типа hasOwnProperty, но этот код будет работать в 99% случаев.

Пример функции:

/**
 * Overwrites obj1's values with obj2's and adds obj2's if non existent in obj1
 * @param obj1
 * @param obj2
 * @returns obj3 a new object based on obj1 and obj2
 */
function merge_options(obj1,obj2){
    var obj3 = {};
    for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; }
    for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; }
    return obj3;
}
1164 голосов
/ 05 октября 2008

jQuery также имеет утилиту для этого: http://api.jquery.com/jQuery.extend/.

Взято из документации jQuery:

// Merge options object into settings object
var settings = { validate: false, limit: 5, name: "foo" };
var options  = { validate: true, name: "bar" };
jQuery.extend(settings, options);

// Now the content of settings object is the following:
// { validate: true, limit: 5, name: "bar" }

Приведенный выше код будет мутировать существующий объект с именем settings.


Если вы хотите создать новый объект без изменения любого аргумента, используйте это:

var defaults = { validate: false, limit: 5, name: "foo" };
var options = { validate: true, name: "bar" };

/* Merge defaults and options, without modifying defaults */
var settings = $.extend({}, defaults, options);

// The content of settings variable is now the following:
// {validate: true, limit: 5, name: "bar"}
// The 'defaults' and 'options' variables remained the same.
329 голосов
/ 05 октября 2014

Harmony ECMAScript 2015 (ES6) указывает Object.assign, который сделает это.

Object.assign(obj1, obj2);

Текущая поддержка браузеров улучшается , но если вы разрабатываете для браузеров, которые не поддерживают, вы можете использовать polyfill .

251 голосов
/ 20 декабря 2008

Я гуглил код для слияния свойств объекта и оказался здесь. Однако, поскольку не было никакого кода для рекурсивного слияния, я написал его сам. (Может быть, расширение jQuery является рекурсивным, кстати?) В любом случае, надеюсь, кто-то найдет его полезным.

(теперь код не использует Object.prototype:)

код

/*
* Recursively merge properties of two objects 
*/
function MergeRecursive(obj1, obj2) {

  for (var p in obj2) {
    try {
      // Property in destination object set; update its value.
      if ( obj2[p].constructor==Object ) {
        obj1[p] = MergeRecursive(obj1[p], obj2[p]);

      } else {
        obj1[p] = obj2[p];

      }

    } catch(e) {
      // Property in destination object not set; create it and set its value.
      obj1[p] = obj2[p];

    }
  }

  return obj1;
}

Пример

o1 = {  a : 1,
        b : 2,
        c : {
          ca : 1,
          cb : 2,
          cc : {
            cca : 100,
            ccb : 200 } } };

o2 = {  a : 10,
        c : {
          ca : 10,
          cb : 20, 
          cc : {
            cca : 101,
            ccb : 202 } } };

o3 = MergeRecursive(o1, o2);

Создает объект o3 как

o3 = {  a : 10,
        b : 2,
        c : {
          ca : 10,
          cb : 20,
          cc : { 
            cca : 101,
            ccb : 202 } } };
173 голосов
/ 19 февраля 2012

Обратите внимание, что underscore.js * extend -метод делает это в одну строку:

_.extend({name : 'moe'}, {age : 50});
=> {name : 'moe', age : 50}
85 голосов
/ 28 января 2014

Подобно jQuery extend (), у вас есть та же функция в AngularJS :

// Merge the 'options' object into the 'settings' object
var settings = {validate: false, limit: 5, name: "foo"};
var options  = {validate: true, name: "bar"};
angular.extend(settings, options);
64 голосов
/ 24 декабря 2011

Мне нужно объединить объекты сегодня, и этот вопрос (и ответы) мне очень помог. Я попробовал некоторые ответы, но ни один из них не соответствовал моим потребностям, поэтому я объединил некоторые ответы, добавил что-то сам и предложил новую функцию слияния. Вот оно:

var merge = function() {
    var obj = {},
        i = 0,
        il = arguments.length,
        key;
    for (; i < il; i++) {
        for (key in arguments[i]) {
            if (arguments[i].hasOwnProperty(key)) {
                obj[key] = arguments[i][key];
            }
        }
    }
    return obj;
};

Некоторые примеры использования:

var t1 = {
    key1: 1,
    key2: "test",
    key3: [5, 2, 76, 21]
};
var t2 = {
    key1: {
        ik1: "hello",
        ik2: "world",
        ik3: 3
    }
};
var t3 = {
    key2: 3,
    key3: {
        t1: 1,
        t2: 2,
        t3: {
            a1: 1,
            a2: 3,
            a4: [21, 3, 42, "asd"]
        }
    }
};

console.log(merge(t1, t2));
console.log(merge(t1, t3));
console.log(merge(t2, t3));
console.log(merge(t1, t2, t3));
console.log(merge({}, t1, { key1: 1 }));
47 голосов
/ 27 января 2017

Вы можете использовать свойства распространения объекта - в настоящее время предложение ECMAScript этапа 3.

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

const obj3 = { ...obj1, ...obj2 };
console.log(obj3);
40 голосов
/ 21 декабря 2008

Указанные решения должны быть изменены, чтобы проверить source.hasOwnProperty(property) в циклах for..in перед назначением - в противном случае вы в конечном итоге копируете свойства всей цепочки прототипов, что редко требуется ...

38 голосов
/ 15 декабря 2015

Объединение свойств N объектов в одной строке кода

Метод Object.assign является частью стандарта ECMAScript 2015 (ES6) и выполняет именно то, что вам нужно. (IE не поддерживается)

var clone = Object.assign({}, obj);

Метод Object.assign () используется для копирования значений всех перечисляемых собственных свойств из одного или нескольких исходных объектов в целевой объект.

Подробнее ...

Полифайл для поддержки старых браузеров:

if (!Object.assign) {
  Object.defineProperty(Object, 'assign', {
    enumerable: false,
    configurable: true,
    writable: true,
    value: function(target) {
      'use strict';
      if (target === undefined || target === null) {
        throw new TypeError('Cannot convert first argument to object');
      }

      var to = Object(target);
      for (var i = 1; i < arguments.length; i++) {
        var nextSource = arguments[i];
        if (nextSource === undefined || nextSource === null) {
          continue;
        }
        nextSource = Object(nextSource);

        var keysArray = Object.keys(nextSource);
        for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
          var nextKey = keysArray[nextIndex];
          var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
          if (desc !== undefined && desc.enumerable) {
            to[nextKey] = nextSource[nextKey];
          }
        }
      }
      return to;
    }
  });
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...