Как динамически объединить свойства двух объектов JavaScript?

2125

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

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

obj1.merge(obj2);

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

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

Теги:
javascript-objects

59 ответов

2111
Лучший ответ

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

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

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

/** There 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 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);

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


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

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

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

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

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

/**
 * Overwrites obj1 values with obj2 and adds obj2 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;
}
  • 62
    Это не работает, если объекты имеют одинаковые атрибуты имени, и вы также хотите объединить атрибуты.
  • 52
    Это делает только поверхностное копирование / слияние. Имеет потенциал, чтобы заглушить много элементов.
Показать ещё 7 комментариев
1087

В 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.
  • 168
    Черт возьми, это называется плохо. Очень маловероятно, чтобы найти его при поиске, как объединить объекты.
  • 162
    Осторожно: переменная «настройки» будет изменена. JQuery не возвращает новый экземпляр. Причина этого (и именования) заключается в том, что .extend () был разработан для расширения объектов, а не для того, чтобы разбирать вещи вместе. Если вы хотите новый объект (например, настройки - это настройки по умолчанию, которые вы не хотите трогать), вы всегда можете jQuery.extend ({}, настройки, опции);
Показать ещё 8 комментариев
338

Harmony ECMAScript 2015 (ES6) определяет Object.assign, который будет делать это.

Object.assign(obj1, obj2);

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

  • 29
    Обратите внимание, что это только поверхностное слияние
  • 0
    Я думаю, что тем временем Object.assign имеет довольно приличное освещение: kangax.github.io/compat-table/es6/…
Показать ещё 5 комментариев
252

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

(Теперь код не использует 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 } } };
  • 8
    Хорошо, но я бы сначала сделал глубокую копию объектов. Этот способ o1 также будет изменен, так как объекты передаются по ссылке.
  • 1
    Это было то, что я искал. Не забудьте проверить, что obj2.hasOwnProperty (p), прежде чем перейти к оператору try catch. В противном случае вы можете получить какую-то другую чушь, сливающуюся сверху в цепочку прототипов.
Показать ещё 8 комментариев
164

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

_.extend({name : 'moe'}, {age : 50});
=> {name : 'moe', age : 50}
  • 35
    Этот пример хорош, так как вы имеете дело с анонимными объектами, но если это не так, то здесь применяется комментарий webmat в ответе jQuery с предупреждением о мутациях, поскольку подчеркивание также изменяет целевой объект . Как и в ответе jQuery, для этого без мутаций просто слиться с пустым объектом: _({}).extend(obj1, obj2);
  • 8
    Есть еще один, который может иметь значение в зависимости от того, чего вы пытаетесь достичь: _.defaults(object, *defaults) «Заполнить нулевые и неопределенные свойства объекта значениями из объектов по умолчанию и вернуть объект».
Показать ещё 2 комментария
88

Подобно 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);
  • 0
    Вы также можете «позаимствовать» определение расширения из источника JQ ...
  • 0
    @juanmf зачем?
Показать ещё 1 комментарий
66

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

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 }));
  • 3
    Единственный тег для вопроса - это javascript , так что это единственный правильный ответ, а также отличный ответ.
  • 3
    хороший ответ, но я думаю, что если свойство присутствует в первом и втором, и вы пытаетесь создать новый объект путем слияния первого и второго, то уникальные, присутствующие в первом объекте, будут потеряны
Показать ещё 4 комментария
45

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

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

const obj3 = { ...obj1, ...obj2 };
console.log(obj3);
  • 0
    Поддержка браузера?
  • 1
    @ Alph.Dev Вы знаете, caniuse.com?
Показать ещё 1 комментарий
39

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

35

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

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

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

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

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

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

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;
    }
  });
}
  • 0
    Что делает «использовать строгий» в старых браузерах или почему оно вообще есть. браузеры, которые поддерживают объект [defineProperty; ключи; getOwnPropertyDescriptor; и т. д.], не совсем старые. Это просто более ранние версии UA 5 поколения.
  • 0
    Спасибо, что Objects.assign что Objects.assign возвращает объединенный объект, чего нет в других ответах. Это более функциональный стиль программирования.
29

Следующие два, вероятно, являются хорошей отправной точкой. lodash также имеет функцию настройки для этих особых потребностей!

_.extend (http://underscorejs.org/#extend)
_.merge (https://lodash.com/docs#merge)

  • 4
    Обратите внимание, что приведенные выше методы изменяют исходный объект.
  • 0
    Метод lodash работал для меня, так как я хотел объединить два объекта и сохранить свойства, вложенные глубиной более одного или двух уровней (а не просто заменить / стереть их).
23

Просто, кстати, все, что вы делаете, это переписывание свойств, а не слияние...

Таким образом, область объектов JavaScript действительно слита: только клавиши в объекте to, которые не являются объектами, будут перезаписаны from. Все остальное будет действительно объединено. Конечно, вы можете изменить это поведение, чтобы не перезаписывать ничего, что существует, только если to[n] is undefined и т.д.:

var realMerge = function (to, from) {

    for (n in from) {

        if (typeof to[n] != 'object') {
            to[n] = from[n];
        } else if (typeof from[n] == 'object') {
            to[n] = realMerge(to[n], from[n]);
        }
    }
    return to;
};

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

var merged = realMerge(obj1, obj2);
  • 3
    Мне очень помогли, подчеркивание JS Exte действительно переписать, а не объединить
  • 0
    Стоит отметить, что typeof array и typeof null вернут 'object' и сломают это.
Показать ещё 3 комментария
21

Вот мой удар, который

  • Поддержка глубокого слияния
  • Не мутирует аргументы
  • Принимает любое количество аргументов
  • Не расширяет прототип объекта
  • Не зависит от другой библиотеки (jQuery, MooTools, Underscore.js и т.д.)
  • Включает проверку hasOwnProperty
  • Короче:)

    /*
        Recursively merge properties and return new object
        obj1 &lt;- obj2 [ &lt;- ... ]
    */
    function merge () {
        var dst = {}
            ,src
            ,p
            ,args = [].splice.call(arguments, 0)
        ;
    
        while (args.length > 0) {
            src = args.splice(0, 1)[0];
            if (toString.call(src) == '[object Object]') {
                for (p in src) {
                    if (src.hasOwnProperty(p)) {
                        if (toString.call(src[p]) == '[object Object]') {
                            dst[p] = merge(dst[p] || {}, src[p]);
                        } else {
                            dst[p] = src[p];
                        }
                    }
                }
            }
        }
    
       return dst;
    }
    

Пример:

a = {
    "p1": "p1a",
    "p2": [
        "a",
        "b",
        "c"
    ],
    "p3": true,
    "p5": null,
    "p6": {
        "p61": "p61a",
        "p62": "p62a",
        "p63": [
            "aa",
            "bb",
            "cc"
        ],
        "p64": {
            "p641": "p641a"
        }
    }
};

b = {
    "p1": "p1b",
    "p2": [
        "d",
        "e",
        "f"
    ],
    "p3": false,
    "p4": true,
    "p6": {
        "p61": "p61b",
        "p64": {
            "p642": "p642b"
        }
    }
};

c = {
    "p1": "p1c",
    "p3": null,
    "p6": {
        "p62": "p62c",
        "p64": {
            "p643": "p641c"
        }
    }
};

d = merge(a, b, c);


/*
    d = {
        "p1": "p1c",
        "p2": [
            "d",
            "e",
            "f"
        ],
        "p3": null,
        "p5": null,
        "p6": {
            "p61": "p61b",
            "p62": "p62c",
            "p63": [
                "aa",
                "bb",
                "cc"
            ],
            "p64": {
                "p641": "p641a",
                "p642": "p642b",
                "p643": "p641c"
            }
        },
        "p4": true
    };
*/
  • 0
    По сравнению с другими, которые я тестировал на этой странице, эта функция действительно рекурсивна (выполняет глубокое слияние) и имитирует то, что jQuery.extend () делает действительно хорошо. Однако было бы лучше, если бы он изменил первый объект / аргумент, чтобы пользователь мог решить, хочет ли он передать пустой объект {} в качестве первого параметра или сделать так, чтобы функция изменила исходный объект. Поэтому, если вы измените dst = {} на dst = arguments[0] это изменит первый объект, который вы передаете объединенному объекту.
  • 1
    Теперь он перестал работать в Chrome. Я думаю, что это плохая идея использовать такую конструкцию toString.call(src) == '[object Object]' для проверки, есть ли объект или нет. typeof src намного лучше. Более того, он превращает массивы в объект (по крайней мере, у меня такое поведение на последнем Chrome).
Показать ещё 1 комментарий
17

Object.assign()

ECMAScript 2015 (ES6)

Это новая технология, являющаяся частью стандарта ECMAScript 2015 (ES6). Эта спецификация технологии была завершена, но проверьте таблицу совместимости для использования и статуса реализации в разных браузерах.

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

var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };

var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1);  // { a: 1, b: 2, c: 3 }, target object itself is changed.
17

Для не слишком сложных объектов вы можете использовать JSON:

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

objMerge = JSON.stringify(obj1) + JSON.stringify(obj2);

// {"food": "pizza","car":"ford"}{"animal":"dog","car":"chevy"}

objMerge = objMerge.replace(/\}\{/, ","); //  \_ replace with comma for valid JSON

objMerge = JSON.parse(objMerge); // { food: 'pizza', animal: 'dog', car: 'chevy'}
// Of same keys in both objects, the last object value is retained_/

Имейте в виду, что в этом примере "} {" не должно встречаться внутри строки!

  • 4
    var so1 = JSON.stringify(obj1); var so2 = JSON.stringify(obj1); objMerge = so1.substr(0, so1.length-1)+","+so2.substr(1); console.info(objMerge);
  • 0
    function merge(obj1, obj2) { return JSON.parse((JSON.stringify(obj1) + JSON.stringify(obj2)) .replace(/\}\{/g, ',').replace(/,\}/g, '}').replace(/\{,/g, '{')); }
Показать ещё 3 комментария
15

Лучший способ сделать это - добавить правильное свойство, которое не перечислимо с помощью Object.defineProperty.

Таким образом, вы все равно сможете перебирать свойства объектов, не имея вновь созданной "расширений", которую вы получили бы, если бы вы создали свойство с Object.prototype.extend.

Надеюсь, это поможет:

Object.defineProperty(Object.prototype, "extend", {
    enumerable: false,
    value: function(from) {
        var props = Object.getOwnPropertyNames(from);
        var dest = this;
        props.forEach(function(name) {
            if (name in dest) {
                var destination = Object.getOwnPropertyDescriptor(from, name);
                Object.defineProperty(dest, name, destination);
            }
        });
        return this;
    }
});

После этого вы можете сделать:

var obj = {
    name: 'stack',
    finish: 'overflow'
}
var replacement = {
    name: 'stock'
};

obj.extend(replacement);

Я просто написал сообщение в блоге об этом здесь: http://onemoredigit.com/post/1527191998/extending-objects-in-node-js

  • 0
    +1 за подсказку Object.defineProperty
  • 0
    Подождите секунду --- код не работает! :( вставил его в jsperf для сравнения с другими алгоритмами слияния, и код завершился ошибкой - расширение функции не существует
Показать ещё 1 комментарий
14

Вы можете просто использовать jQuery extend

var obj1 = { val1: false, limit: 5, name: "foo" };
var obj2 = { val2: true, name: "bar" };

jQuery.extend(obj1, obj2);

Теперь obj1 содержит все значения obj1 и obj2

  • 2
    obj1 будет содержать все значения, а не obj2. Вы расширяете первый объект. jQuery.extend( target [, object1 ] [, objectN ] )
  • 5
    Этот вопрос не о jQuery. JavaScript! = JQuery
Показать ещё 1 комментарий
14

Там есть библиотека под названием deepmerge на GitHub: Кажется, что получается какая-то тяга. Он является автономным, доступным как через npm, так и менеджерами пакетов bower.

Я был бы склонен использовать или улучшать это, вместо того, чтобы копировать код из ответов.

11

Prototype имеет следующее:

Object.extend = function(destination,source) {
    for (var property in source)
        destination[property] = source[property];
    return destination;
}

obj1.extend(obj2) сделает то, что вы хотите.

  • 6
    Вы имели в виду Object.prototype.extend? В любом случае, не рекомендуется расширять Object.prototype. -1.
  • 0
    Если подумать, то, вероятно, это должен быть Object.prototype а не Object ... Хорошая идея или нет, это то, что делает фреймворк prototype.js , и поэтому, если вы используете его или другой фреймворк, который зависит от него, Object.prototype уже будет расширен с extend .
Показать ещё 7 комментариев
10

Просто, если кто-то использует Google Closure Library:

goog.require('goog.object');
var a = {'a': 1, 'b': 2};
var b = {'b': 3, 'c': 4};
goog.object.extend(a, b);
// Now object a == {'a': 1, 'b': 3, 'c': 4};

Подобная вспомогательная функция существует для массива:

var a = [1, 2];
var b = [3, 4];
goog.array.extend(a, b); // Extends array 'a'
goog.array.concat(a, b); // Returns concatenation of array 'a' and 'b'
8

Слияние объектов просто.

var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog', car: 'BMW' }
var obj3 = {a: "A"}


var mergedObj = Object.assign(obj1,obj2,obj3)

console.log(mergedObj);

Объекты объединяются справа налево, это означает, что объекты, которые имеют одинаковые свойства, как объекты справа от них, будут переопределены.

В этом примере obj2.car переопределяет obj1.car

8

Я продлил метод Дэвида Коллиера:

  • Добавлена ​​возможность объединения нескольких объектов
  • Поддержка глубоких объектов
  • переопределить параметр (который обнаружил, что последний параметр является логическим)

Если переопределить значение false, свойство не будет переопределено, но будут добавлены новые свойства.

Использование: obj.merge(слияние... [, переопределение]);

Вот мой код:

Object.defineProperty(Object.prototype, "merge", {
    enumerable: false,
    value: function () {
        var override = true,
            dest = this,
            len = arguments.length,
            props, merge, i, from;

        if (typeof(arguments[arguments.length - 1]) === "boolean") {
            override = arguments[arguments.length - 1];
            len = arguments.length - 1;
        }

        for (i = 0; i < len; i++) {
            from = arguments[i];
            if (from != null) {
                Object.getOwnPropertyNames(from).forEach(function (name) {
                    var descriptor;

                    // nesting
                    if ((typeof(dest[name]) === "object" || typeof(dest[name]) === "undefined")
                            && typeof(from[name]) === "object") {

                        // ensure proper types (Array rsp Object)
                        if (typeof(dest[name]) === "undefined") {
                            dest[name] = Array.isArray(from[name]) ? [] : {};
                        }
                        if (override) {
                            if (!Array.isArray(dest[name]) && Array.isArray(from[name])) {
                                dest[name] = [];
                            }
                            else if (Array.isArray(dest[name]) && !Array.isArray(from[name])) {
                                dest[name] = {};
                            }
                        }
                        dest[name].merge(from[name], override);
                    } 

                    // flat properties
                    else if ((name in dest && override) || !(name in dest)) {
                        descriptor = Object.getOwnPropertyDescriptor(from, name);
                        if (descriptor.configurable) {
                            Object.defineProperty(dest, name, descriptor);
                        }
                    }
                });
            }
        }
        return this;
    }
});

Примеры и тестовые примеры:

function clone (obj) {
    return JSON.parse(JSON.stringify(obj));
}
var obj = {
    name : "trick",
    value : "value"
};

var mergeObj = {
    name : "truck",
    value2 : "value2"
};

var mergeObj2 = {
    name : "track",
    value : "mergeObj2",
    value2 : "value2-mergeObj2",
    value3 : "value3"
};

assertTrue("Standard", clone(obj).merge(mergeObj).equals({
    name : "truck",
    value : "value",
    value2 : "value2"
}));

assertTrue("Standard no Override", clone(obj).merge(mergeObj, false).equals({
    name : "trick",
    value : "value",
    value2 : "value2"
}));

assertTrue("Multiple", clone(obj).merge(mergeObj, mergeObj2).equals({
    name : "track",
    value : "mergeObj2",
    value2 : "value2-mergeObj2",
    value3 : "value3"
}));

assertTrue("Multiple no Override", clone(obj).merge(mergeObj, mergeObj2, false).equals({
    name : "trick",
    value : "value",
    value2 : "value2",
    value3 : "value3"
}));

var deep = {
    first : {
        name : "trick",
        val : "value"
    },
    second : {
        foo : "bar"
    }
};

var deepMerge = {
    first : {
        name : "track",
        anotherVal : "wohoo"
    },
    second : {
        foo : "baz",
        bar : "bam"
    },
    v : "on first layer"
};

assertTrue("Deep merges", clone(deep).merge(deepMerge).equals({
    first : {
        name : "track",
        val : "value",
        anotherVal : "wohoo"
    },
    second : {
        foo : "baz",
        bar : "bam"
    },
    v : "on first layer"
}));

assertTrue("Deep merges no override", clone(deep).merge(deepMerge, false).equals({
    first : {
        name : "trick",
        val : "value",
        anotherVal : "wohoo"
    },
    second : {
        foo : "bar",
        bar : "bam"
    },
    v : "on first layer"
}));

var obj1 = {a: 1, b: "hello"};
obj1.merge({c: 3});
assertTrue(obj1.equals({a: 1, b: "hello", c: 3}));

obj1.merge({a: 2, b: "mom", d: "new property"}, false);
assertTrue(obj1.equals({a: 1, b: "hello", c: 3, d: "new property"}));

var obj2 = {};
obj2.merge({a: 1}, {b: 2}, {a: 3});
assertTrue(obj2.equals({a: 3, b: 2}));

var a = [];
var b = [1, [2, 3], 4];
a.merge(b);
assertEquals(1, a[0]);
assertEquals([2, 3], a[1]);
assertEquals(4, a[2]);


var o1 = {};
var o2 = {a: 1, b: {c: 2}};
var o3 = {d: 3};
o1.merge(o2, o3);
assertTrue(o1.equals({a: 1, b: {c: 2}, d: 3}));
o1.b.c = 99;
assertTrue(o2.equals({a: 1, b: {c: 2}}));

// checking types with arrays and objects
var bo;
a = [];
bo = [1, {0:2, 1:3}, 4];
b = [1, [2, 3], 4];

a.merge(b);
assertTrue("Array stays Array?", Array.isArray(a[1]));

a = [];
a.merge(bo);
assertTrue("Object stays Object?", !Array.isArray(a[1]));

a = [];
a.merge(b);
a.merge(bo);
assertTrue("Object overrides Array", !Array.isArray(a[1]));

a = [];
a.merge(b);
a.merge(bo, false);
assertTrue("Object does not override Array", Array.isArray(a[1]));

a = [];
a.merge(bo);
a.merge(b);
assertTrue("Array overrides Object", Array.isArray(a[1]));

a = [];
a.merge(bo);
a.merge(b, false);
assertTrue("Array does not override Object", !Array.isArray(a[1]));

Мой метод equals можно найти здесь: Сравнение объектов в JavaScript

8

В MooTools, Object.merge():

Object.merge(obj1, obj2);
7

В Ext JS 4 это можно сделать следующим образом:

var mergedObject = Ext.Object.merge(object1, object2)

// Or shorter:
var mergedObject2 = Ext.merge(object1, object2)

См. merge (object): Object.

  • 1
    Остерегайтесь ошибки EXTJS-9173 в EXT.Object.merge, так как после +2 лет все еще не решена
6

На основе Markus ' и vsync' answer это расширенная версия. Функция принимает любое количество аргументов. Его можно использовать для установки свойств на узлах DOM и делает глубокие копии значений. Однако первый аргумент задается ссылкой.

Чтобы обнаружить DOM node, используется функция isDOMNode() (см. Stack вопрос с переполнением JavaScript isDOM. Как вы проверяете, является ли объект JavaScript объектом DOM?)

Он был протестирован в Opera 11, Firefox 6, Internet Explorer 8 и Google Chrome 16.

код

function mergeRecursive() {

  // _mergeRecursive does the actual job with two arguments.
  var _mergeRecursive = function (dst, src) {
    if (isDOMNode(src) || typeof src !== 'object' || src === null) {
      return dst;
    }

    for (var p in src) {
      if (!src.hasOwnProperty(p))
        continue;
      if (src[p] === undefined)
        continue;
      if ( typeof src[p] !== 'object' || src[p] === null) {
        dst[p] = src[p];
      } else if (typeof dst[p]!=='object' || dst[p] === null) {
        dst[p] = _mergeRecursive(src[p].constructor===Array ? [] : {}, src[p]);
      } else {
        _mergeRecursive(dst[p], src[p]);
      }
    }
    return dst;
  }

  // Loop through arguments and merge them into the first argument.
  var out = arguments[0];
  if (typeof out !== 'object' || out === null)
    return out;
  for (var i = 1, il = arguments.length; i < il; i++) {
    _mergeRecursive(out, arguments[i]);
  }
  return out;
}

Некоторые примеры

Установите innerHTML и стиль HTML-элемента

mergeRecursive(
  document.getElementById('mydiv'),
  {style: {border: '5px solid green', color: 'red'}},
  {innerHTML: 'Hello world!'});

Объединить массивы и объекты. Обратите внимание, что undefined может использоваться для сохранения значений в файле lefthand/object.

o = mergeRecursive({a:'a'}, [1,2,3], [undefined, null, [30,31]], {a:undefined, b:'b'});
// o = {0:1, 1:null, 2:[30,31], a:'a', b:'b'}

Любой аргумент, не являющийся объектом JavaScript (включая null), будет проигнорирован. За исключением первого аргумента, также удаляются узлы DOM. Помните, что, например, строки, созданные как новые String(), фактически являются объектами.

o = mergeRecursive({a:'a'}, 1, true, null, undefined, [1,2,3], 'bc', new String('de'));
// o = {0:'d', 1:'e', 2:3, a:'a'}

Если вы хотите объединить два объекта в новый (не затрагивая ни один из двух), поставьте {} в качестве первого аргумента

var a={}, b={b:'abc'}, c={c:'cde'}, o;
o = mergeRecursive(a, b, c);
// o===a is true, o===b is false, o===c is false

Изменить (от ReaperSoon):

Чтобы также объединить массивы

function mergeRecursive(obj1, obj2) {
  if (Array.isArray(obj2)) { return obj1.concat(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 if (Array.isArray(obj2[p])) {
        obj1[p] = obj1[p].concat(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;
}
5

С 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}
4

Ничего себе.. это первое сообщение StackOverflow, которое я видел с несколькими страницами. Извинения за добавление еще одного "ответа"

Этот метод предназначен для ES5 и ранее - есть много других ответов, касающихся ES6.

Я не видел никакого "глубокого" слияния объекта с использованием свойства arguments. Вот мой ответ - компактный и рекурсивный, позволяющий передавать неограниченные аргументы объекта:

function extend() {
    for (var o = {}, i = 0; i < arguments.length; i++) {
        // if (arguments[i].constructor !== Object) continue;
        for (var k in arguments[i]) {
            if (arguments[i].hasOwnProperty(k)) {
                o[k] = arguments[i][k].constructor === Object ? extend(o[k] || {}, arguments[i][k]) : arguments[i][k];
            }
        }
    }
    return o;
}

Часть, которая закомментирована, является необязательной. Она просто пропускает переданные аргументы, которые не являются объектами (предотвращая ошибки).

Пример:

extend({
    api: 1,
    params: {
        query: 'hello'
    }
}, {
    params: {
        query: 'there'
    }
});

// outputs {api: 1, params: {query: 'there'}}

Этот ответ теперь - только падение в океане...

4

Вы должны использовать lodash defaultsDeep

_.defaultsDeep({ 'user': { 'name': 'barney' } }, { 'user': { 'name': 'fred', 'age': 36 } });
// → { 'user': { 'name': 'barney', 'age': 36 } }
4

Следует отметить, что версия из 140byt.es collection решает задачу в минимальном пространстве и стоит попробовать для этой цели:

код:

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

Здесь оригинал Gist.

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

// result
result: {food: "pizza", car: "ford", animal: "dog"}

Использование jQuery.extend() - Link

// Merge obj1 & obj2 to result
var result1 = $.extend( {}, obj1, obj2 );

Использование _.merge() - Link

// Merge obj1 & obj2 to result
var result2 = _.merge( {}, obj1, obj2 );

Использование _.extend() - Ссылка

// Merge obj1 & obj2 to result
var result3 = _.extend( {}, obj1, obj2 );

Использование Object.assign() ECMAScript 2015 (ES6) - Ссылка

// Merge obj1 & obj2 to result
var result4 = Object.assign( {}, obj1, obj2 );

Вывод всех

obj1: { animal: 'dog' }
obj2: { food: 'pizza', car: 'ford' }
result1: {food: "pizza", car: "ford", animal: "dog"}
result2: {food: "pizza", car: "ford", animal: "dog"}
result3: {food: "pizza", car: "ford", animal: "dog"}
result4: {food: "pizza", car: "ford", animal: "dog"}
3

Я использую следующее, что в чистом 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

Мой способ:

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

:)

2

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 )
  • 4
    Это сбрасывается со счетов, если o2 содержит какие-либо свойства, которые еще не существуют в o1, именно поэтому у Markus есть удаленная попытка / отлов. Ваш пример работает только потому, что все свойства o2 уже существуют в o1. Так что это не слияние и не лучше!
  • 0
    нет, это не подводит, я только что попробовал то, что вы сказали с успехом.
Показать ещё 5 комментариев
2

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

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

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

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

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

Так, например, обертывание функции...... Object.getOwnPropertyNames(from).forEach... "с помощью" if (from!= null) {...} "предотвратит эту ошибку.

2

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

//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 }
1

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

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

Вы можете объединить объекты, выполнив мой метод

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

Для тех, кто использует 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
    Это не встроенная библиотека, это модуль NPM.
1

В YUI Y.merge должен получить работу сделано:

Y.merge(obj1, obj2, obj3....) 
1

Я начинаю работать с 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

Правильная реализация в Prototype должна выглядеть так:

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

obj1 = Object.extend(obj1, obj2);
0

let obj1 = {a:1, b:2};
let obj2 = {c:3, d:4};
let merged = {...obj1, ...obj2};
console.log(merged);
0

С помощью следующего помощника вы можете объединить два объекта в один новый объект:

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

Это включает в себя немного меньше кода и немного быстрее.

0

Мы можем собрать пустой объект и объединить их 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)
0

Собственный однострочный совместимый с ES5:

var merged = [obj1, obj2].reduce(function(a, o) { for(k in o) a[k] = o[k]; return a; }, {})
0

Объединение JSON совместимых объектов JavaScript

Я рекомендую использовать и использовать неразрушающие методы, которые не изменяют исходный исходный код, "Object.assign" - это разрушительный метод, и он также не настолько дружелюбен к продукту, потому что он перестает работать с более ранними браузерами, и у вас есть никоим образом не исправлять его, используя альтернативу.

Объединение объектов JS всегда будет вне досягаемости или неполным независимо от решения. Но слияние совместимых с JSON объектов - всего лишь один шаг от возможности написать простую и переносимую часть кода неразрушающего метода слияния рядов объектов JS в возвращаемый мастер, содержащий все уникальные имена свойств и их соответствующие значения, синтезированные в один главный объект по назначению.

Имея в виду, что MSIE8 - это первый браузер, добавивший встроенную поддержку объекта JSON, является большим облегчением и повторным использованием уже существующей технологии, всегда приветствуется.

Ограничение вашего кода стандартными объектами, совместимыми с JSON, является скорее преимуществом, чем ограничением, поскольку эти объекты также могут передаваться через Интернет. И, конечно же, для тех, кто хочет более глубокую обратную совместимость, всегда есть json plug, методы которого легко могут быть назначены переменной 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, все объекты остаются нетронутыми и в исходном состоянии (если вы сделали что-то неправильно и вам нужно изменить порядок слияния объектов или использовать их отдельно для какой-либо другой операции перед слиянием их снова).

Число аргументов Merge также ограничено только пределом длины аргументов [который огромен]. Собственно поддерживаемый JSON parse/strify уже оптимизирован машиной, что означает: он должен быть быстрее любой скриптовой формы JS-цикла. Итерация по заданным аргументам выполняется с использованием while - самого быстрого цикла в JS.

Не вредно кратко упомянуть тот факт, что мы уже знаем, что повторяющиеся свойства уникальных меток объектов (ключей) будут перезаписаны более поздним объектом, содержащим одну и ту же метку ключа, что означает, что вы контролируете, какое свойство используя предыдущий, просто упорядочив или переупорядочив список аргументов. И преимущество получения чистого и обновленного основного объекта без дубликатов в качестве конечного результата.

0

Возможный способ достижения этого - следующее.

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 будет "бросать" "Ошибка"

0

Если вы используете Dojo Toolkit, то лучшим способом слияния двух объектов является использование mixin.

Ниже приведен образец для Dojo Mixer Toolkit:

// Dojo 1.7+ (AMD)
require(["dojo/_base/lang"], function(lang){
  var a = { b:"c", d:"e" };
  lang.mixin(a, { d:"f", g:"h" });
  console.log(a); // b:c, d:f, g:h
});

// Dojo < 1.7
var a = { b:"c", d:"e" };
dojo.mixin(a, { d:"f", g:"h" });
console.log(a); // b:c, d:f, g:h

Подробнее см. mixin.

0

Другой метод:

function concat_collection(obj1, obj2) {
    var i;
    var arr = new Array();

    var len1 = obj1.length;
    for (i=0; i<len1; i++) {
        arr.push(obj1[i]);
    }

    var len2 = obj2.length;
    for (i=0; i<len2; i++) {
        arr.push(obj2[i]);
    }

    return arr;
}

var ELEMENTS = concat_collection(A,B);
for(var i = 0; i < ELEMENTS.length; i++) {
    alert(ELEMENTS[i].value);
}
0

Это решение создает новый объект и способно обрабатывать несколько объектов.

Кроме того, он рекурсивный, и вы можете выбрать погодные условия > переписать значения и Объекты.

    function extendObjects() {

        var newObject        = {};
        var overwriteValues  = false;
        var overwriteObjects = false;

        for ( var indexArgument = 0; indexArgument < arguments.length; indexArgument++ ) {

            if ( typeof arguments[indexArgument] !== 'object' ) {

                if ( arguments[indexArgument] == 'overwriteValues_True' ) {

                    overwriteValues = true;            
                } else if ( arguments[indexArgument] == 'overwriteValues_False' ) {

                    overwriteValues = false;                             
                } else if ( arguments[indexArgument] == 'overwriteObjects_True' ) {

                    overwriteObjects = true;     
                } else if ( arguments[indexArgument] == 'overwriteObjects_False' ) {

                    overwriteObjects = false; 
                }

            } else {

                extendObject( arguments[indexArgument], newObject, overwriteValues, overwriteObjects );
            }

        }

        function extendObject( object, extendedObject, overwriteValues, overwriteObjects ) {

            for ( var indexObject in object ) {

                if ( typeof object[indexObject] === 'object' ) {

                    if ( typeof extendedObject[indexObject] === "undefined" || overwriteObjects ) {
                        extendedObject[indexObject] = object[indexObject];
                    }

                    extendObject( object[indexObject], extendedObject[indexObject], overwriteValues, overwriteObjects );

                } else {

                    if ( typeof extendedObject[indexObject] === "undefined" || overwriteValues ) {
                        extendedObject[indexObject] = object[indexObject];
                    }

                }

            }     

            return extendedObject;

        }

        return newObject;
    }

    var object1           = { a : 1, b : 2, testArr : [888, { innArr : 1 }, 777 ], data : { e : 12, c : { lol : 1 }, rofl : { O : 3 } } };
    var object2           = { a : 6, b : 9, data : { a : 17, b : 18, e : 13, rofl : { O : 99, copter : { mao : 1 } } }, hexa : { tetra : 66 } };
    var object3           = { f : 13, g : 666, a : 333, data : { c : { xD : 45 } }, testArr : [888, { innArr : 3 }, 555 ]  };

    var newExtendedObject = extendObjects( 'overwriteValues_False', 'overwriteObjects_False', object1, object2, object3 );

Содержимое newExtendedObject:

{"a":1,"b":2,"testArr":[888,{"innArr":1},777],"data":{"e":12,"c":{"lol":1,"xD":45},"rofl":{"O":3,"copter":{"mao":1}},"a":17,"b":18},"hexa":{"tetra":66},"f":13,"g":666}

Fiddle: http://jsfiddle.net/o0gb2umb/

0

Я использовал 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 перед конкатенацией.

0

Вы можете назначить каждому объекту объединение по умолчанию (возможно, "наследовать" лучшее имя):

Он должен работать с любыми объектами или инстанцированными функциями.

Приведенный ниже код обрабатывает переопределенные значения, если это необходимо:

Object.prototype.merge = function(obj, override) {
// Don't override by default

    for (var key in obj) {
        var n = obj[key];
        var t = this[key];
        this[key] = (override && t) ? n : t;
    };

};

Ниже приведены тестовые данные:

var Mammal = function () {
    this.eyes = 2;
    this.thinking_brain = false;
    this.say = function () {
    console.log('screaming like a mammal')};
}

var Human = function () {
    this.thinking_brain = true;
    this.say = function() {console.log('shouting like a human')};
}

john = new Human();

// Extend mammal, but do not override from mammal
john.merge(new Mammal());
john.say();

// Extend mammal and override from mammal
john.merge(new Mammal(), true);
john.say();
0
A={a:1,b:function(){alert(9)}}
B={a:2,c:3}
A.merge = function(){for(var i in B){A[i]=B[i]}}
A.merge()

Результат: {a: 2, c: 3, b: function()}

  • 0
    Кстати, в dojo есть функция mixin, так что dojo.mixin (A, B) справится с задачей
0

Это объединяет obj в "default" 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}}
0
function extend()
{ 
    var o = {}; 

    for (var i in arguments)
    { 
        var s = arguments[i]; 

        for (var i in s)
        { 
            o[i] = s[i]; 
        } 
    } 

    return o;
}
-1

Если вам нужно глубокое слияние, которое также будет "объединять" массивы, объединив их в результате, то эта функция ES6 может быть тем, что вам нужно:

function deepMerge(a, b) {
    // If neither is an object, return one of them:
    if (Object(a) !== a && Object(b) !== b) return b || a;
    // Replace remaining primitive by empty object/array
    if (Object(a) !== a) a = Array.isArray(b) ? [] : {};
    if (Object(b) !== b) b = Array.isArray(a) ? [] : {};
    // Treat arrays differently:
    if (Array.isArray(a) && Array.isArray(b)) {
        // Merging arrays is interpreted as concatenation of their deep clones:
        return [...a.map(v => deepMerge(v)), ...b.map(v => deepMerge(v))];
    } else {
        // Get the keys that exist in either object
        var keys = new Set([...Object.keys(a),...Object.keys(b)]);
        // Recurse and assign to new object
        return Object.assign({}, ...Array.from(keys,
            key => ({ [key]: deepMerge(a[key], b[key]) }) ));
    }
}

// Sample data for demo:
var a = {
    groups: [{
        group: [{
            name: 'John',
            age: 12
        },{
            name: 'Mary',
            age: 20
        }],
        groupName: 'Pair'
    }],
    config: {
        color: 'blue',
        range: 'far'
    }
};


var b = {
    groups: [{
        group: [{
            name: 'Bill',
            age: 15
        }],
        groupName: 'Loner'
    }],
    config: {
        range: 'close',
        strength: 'average'
    }
};

var merged = deepMerge(a, b);

console.log(merged);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Обратите внимание, что если только одна аргумента передается этой функции, она действует как функция глубокого клонирования.

-2

использовать object.assign

Object.prototype.assign = Object.assign && function () {
    var a = [];
    for (var _i = 0; _i < arguments.length; _i++) {
        a[_i] = arguments[_i];
    }
    var src = a.slice(1);
    var target = a[0];
    for (var o in src) {
        if (src.hasOwnProperty(o)) {
            var keys = Object.keys(src[o]);
            var _src = src[o];
            for (var k in keys) {
                if (keys.hasOwnProperty(k)) {
                    var _key = keys[k];
                    target[_key] = _src[_key];
                }
            }
        }
    }
    return target;
};
-2
<pre>
/**
This script can merge two multi dimensional associative array/objects in javascript by comparing given object with its reference and 
will remove additional given keys, adding missed parameteres and also validating values without overhead. Also it will return the default values if no input presented with re-usable reference!
Tested on IE8 and greater.
**/
var module = (function(){
    //To make our reference variable onchangable, have to put it into a function which is fster and more efficient than "JSON.parse(JSON.stringify(VARIABLE))"
    var _defs = function(){
            return {
                   //string, number and boolean are actually regex based validation keys on input values.
                a: ["string", 'Defaul value for "a"'],
                b: ["number", 300],
                c: ["boolean", true],
                d: {
                  da: ["boolean", true],
                  db: ["string", 'Defaul value for "db"'],
                  dc: {
                    dca: ["number", 200],
                    dcb: ["string", 'Default value for "dcb"'],
                    dcc: ["number", 500],
                    dcd: ["boolean", true]
                  },
                  dce: ["string", 'Default value for "dce"'],
                },
                e: ["number", 200],
                f: ["boolean", 0],
                g: ["", 'This is an internal extra parameter']
            }
        }

        var _validation = {
                number: function (defaultValue, userValue) {
                  if(/^[0-9]+$/.test(userValue)) //Only numbers allowed
                    return userValue;
                  else return defaultValue;
                },
                string: function (defaultValue, userValue) {
                  if(/^[a-zA-Z\s]*$/.test(userValue)) //Only A to Z case insentitive with space aloowed.
                    return userValue;
                  else return defaultValue;
                },
                boolean: function (defaultValue, userValue) {
                  if(typeof userValue === 'boolean') //True or False or 0 ,1
                    return userValue;
                  else return defaultValue;
                }
        }

        var _uniqueMerge = function(opts, _ref){
                for(var key in _ref)
                    if (_ref && _ref[key] && _ref[key].constructor && _ref[key].constructor === Object)
                      _ref[key] = _uniqueMerge((opts ? opts[key] : null ), _ref[key] );
                    else if(opts && opts.hasOwnProperty(key))
                      _ref[key] = _validation[_ref[key][0]](_ref[key][1], opts[key]); //or without validation on user enties => ref[key] = obj[key]
                    else _ref[key] = _ref[key][1];
                return _ref;
        }
        var _get = function(inputs){
            return _uniqueMerge(inputs, _defs());
        }
        return {
            options: function(){
            return _get(arguments[0] || null); // for more safety and control on number of input variables! used --> ( arguments[0] || null )
            }
        }
})();


//How to use it:    

input_one = { 
    a : "Hello World", 
  //b : ["number", 400], //User missed this parameter
    c: "Hi",
    d : {
        da : false,
        db : "Hellow! World", // ! is not allowed
        dc : {
            dca : 10,
            dcb : "My String",
            dcc: "3thString",
            dcd : false
      },
      dce: "ANOTHER STRING",
    },
    e: 40,
    f: true,
    z: 'x'
};
console.log( JSON.stringify( module.options(input_one), null ,2 ) );
//Output:
/*
{
  "a": "Hello World",
  "b": 300,
  "c": true,
  "d": {
    "da": false,
    "db": "Defaul value for \"db\"",
    "dc": {
      "dca": 10,
      "dcb": "My String",
      "dcc": 500,
      "dcd": false
    },
    "dce": "ANOTHER STRING"
  },
  "e": 40,
  "f": true,
  "g": "This is an internal extra parameter"
}
*/
input_two = { 
    a : 32,
  //b : ["number", 400], //User missed this parameter
    c: "Hi",
    d : {
        da : false,
        db : "HelloWorld",
        dc : {
            dca : 10,
            dcb : "My String",
            dcd : false
      },
      dce: 73,
    }
};
console.log( JSON.stringify( module.options(input_two), null ,2 ) );
//output
/*
{
  "a": "Defaul value for \"a\"",
  "b": 300,
  "c": true,
  "d": {
    "da": false,
    "db": "HelloWorld",
    "dc": {
      "dca": 10,
      "dcb": "My String",
      "dcc": 500,
      "dcd": false
    },
    "dce": "Default value for \"dce\""
  },
  "e": 200,
  "f": 0,
  "g": "This is an internal extra parameter"
}
*/
//Empty input will return the default values!
console.log( JSON.stringify( module.options(), null ,2 ) );     
//Output
/*  
{
  "a": "Defaul value for \"a\"",
  "b": 300,
  "c": true,
  "d": {
    "da": true,
    "db": "Defaul value for \"db\"",
    "dc": {
      "dca": 200,
      "dcb": "Default value for \"dcb\"",
      "dcc": 500,
      "dcd": true
    },
    "dce": "Default value for \"dce\""
  },
  "e": 200,
  "f": 0,
  "g": "This is an internal extra parameter"
}
*/
</pre>
-2

Вы можете сделать следующее в EcmaScript2016

Исправление: это предложение на этапе 3, но он всегда работал у меня

const objA = {
  attrA: 'hello',
  attrB: true
}

const objB = {
  attrC: 2
}

const mergedObj = {...objA, ...objB}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню