it-swarm.com.ru

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

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

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

obj1.merge(obj2);

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

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

2072
JC Grubbs

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;
}
2312
John Millikin

у 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.
1149
Avdi

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

Object.assign(obj1, obj2);

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

323
NanoWizard

Я гуглил код для слияния свойств объекта и оказался здесь. Однако, поскольку не было никакого кода для рекурсивного слияния, я написал его сам. (Может быть, расширение 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 like

o3 = {  a : 10,
        b : 2,
        c : {
          ca : 10,
          cb : 20,
          cc : { 
            cca : 101,
            ccb : 202 } } };
241
Markus

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

_.extend({name : 'moe'}, {age : 50});
=> {name : 'moe', age : 50}
172
Industrial

Подобно 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);
84
AndreasE

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

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 }));
63
Emre Erkan

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

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

const obj3 = { ...obj1, ...obj2 };
console.log(obj3);

46
Jaime Asm

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

39
Christoph

Объединить свойства 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;
    }
  });
}
37
Eugene Tiurin

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

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

31
appsmatics

Кстати, все, что вы делаете, это перезаписывает свойства, а не объединяет ...

Вот как действительно объединилась область объектов 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);
23
Andreas Linden

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

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

    /*
        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
    };
*/
21
Paul Spaulding

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
Reza Roshan

Для не слишком сложных объектов вы можете использовать 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's value is retained_/

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

17
Algy

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

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

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

 Object.defineProperty (Object.prototype, "extended", {
 Enumerable: false, 
 Value: function (from) {
 Var props = Object.getOwnPropertyNames (from); 
 Var dest = this; 
 props.forEach (function (name) {
 if (имя в dest) {
 var destination = Object.getOwnPropertyDescriptor (from, name); 
 Object.defineProperty (dest, имя, пункт назначения); 
} 
}); 
 вернуть это; 
} 
}); 

Как только у вас это заработает, вы можете сделать:

 var obj = {
 имя: «стек», 
 finish: 'overflow' 
} 
 var replace = {
 name: 'stock' 
}; 

 obj.extend (замена); 

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

15
David Coallier

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

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

jQuery.extend(obj1, obj2);

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

14
Dinusha

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

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

14
antitoxic

Прототип имеет это:

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

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

11
ephemient

Просто если кто-то использует 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'
10
Paweł Szczur

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

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

Если override имеет значение 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]));

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

8
gossi

В MooTools , есть Object.merge () :

Object.merge(obj1, obj2);
8
philfreo

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

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
Legends

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

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

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

Смотрите объединение (объект): Объект.

7
Mark

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

Для обнаружения узла DOM используется функция isDOMNode () (см. Вопрос переполнения стека 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 может использоваться для сохранения значений в левом массиве/объекте.

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 (включая ноль), будет игнорироваться. За исключением первого аргумента, также DOM-узлы отбрасываются. Помните, что строки, созданные как new 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;
}
6
Snoozer Man

Ого ... это первый пост StackOverflow, который я видел на нескольких страницах. Извиняюсь за добавление еще одного "ответа"

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

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

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

Этот ответ - теперь капля в море ...

6
Logan

С 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}
5
devmao

Стоит отметить, что версия из коллекции 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);

Вот оригинальный Gist .

4
pagid

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

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

Я использую следующее в чистом 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];
      }
    }
  }
};
3
Etherealone
var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog' }

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

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

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

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

// 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
TinhNQ

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
Paweł Otto

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
vsync

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

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

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

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

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

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

2
user909278

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

//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
RobKohr

Мой метод:

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
bravedick

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

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
Nishant Kumar

Я как бы начинаю с 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
antony

В YUIY.merge должны выполнить работу:

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

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

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

obj1 = Object.extend(obj1, obj2);
1
Tobi

Для тех, кто использует 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
Ryan Walls

Вы можете объединить объекты, следуя моему методу

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
Sherali Turdiyev

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

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

Слияние 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. 

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

0
Bekim Bacaj

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

Кроме того, это recursive, и вы можете выбрать погоду, которую вы хотите, чтобы перезаписать значения и Objects.

    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}

Скрипка: http://jsfiddle.net/o0gb2umb/

0
Scdev

Я использовал 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
Egor Kloos

Возможный способ добиться этого заключается в следующем.

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 выдает «Error»

0
Yaki Klein

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

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
gildniy

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

0
Tejas Savaliya
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
jleviaguirre

Это объединяет 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}}
0
Aram Kocharyan

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

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

Ниже приведен пример миксина Dojo 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
Vikash Pandey

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

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

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

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
Paul

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

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
T.Todua