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

avatar
JC Grubbs
5 октября 2008 в 00:30
1538207
68
2831

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

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

obj1.merge(obj2);

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

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

Источник
ToolmakerSteve
3 октября 2019 в 21:42
0

Стоит отметить этот ответ на аналогичный вопрос, в котором показано, как объединить «на один уровень ниже». То есть он объединяет значения повторяющихся ключей (вместо перезаписи первого значения вторым значением), но не выполняет рекурсию дальше этого. IMHO, это хороший чистый код для этой задачи.

ToolmakerSteve
4 октября 2019 в 12:30
0

Кстати, несколько верхних ответов выполняют «неглубокое» слияние: если один и тот же ключ существует как в obj1, так и в obj2, значение в obj2 сохраняется, значение в obj1 отбрасывается. Например. если в примере вопроса было var obj2 = { animal: 'dog', food: 'bone' };, слияние было бы { food: 'bone', car: 'ford', animal: 'dog' }. Если вы работаете с «вложенными данными» и хотите «глубокое слияние», поищите ответы, в которых упоминается «глубокое слияние» или «рекурсия». Если у вас есть значения arrays, используйте параметр "arrayMerge" в github "TehShrike / deepmerge", как упоминалось здесь.

Soura Sankar Ghosh
11 января 2020 в 13:00
0

Пожалуйста, перейдите по ссылке ниже coderhelper.com/questions/171251/… Оператор распространения, который является новой функцией в версии ES6.

Ответы (68)

avatar
Derek Ziemba
29 мая 2021 в 04:15
3390

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

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

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

merged теперь объединение obj1 и obj2. Свойства в obj2 заменят свойства в obj1.

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

Здесь также документация MDN для этого синтаксиса. Если вы используете babel, вам понадобится плагин babel-plugin-transform-object-rest-spread, чтобы он работал.

Стандартный метод 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;
}
Xiè Jìléi
24 октября 2010 в 10:56
106

Это не работает, если объекты имеют атрибуты с одинаковыми именами, и вы также можете объединить атрибуты.

Jay Taylor
2 июня 2011 в 15:39
77

Это только поверхностное копирование / слияние. Имеет потенциал уничтожить множество элементов.

thejonwithnoh
7 мая 2016 в 04:18
55

+1 за признание того, что некоторые бедняги вынуждены использовать фреймворки, которые гадят на всех их прототипах ...

avatar
24 апреля 2022 в 05:01
0

Используйте это

var t=merge({test:123},{mysecondTest:{blub:{test2:'string'},args:{'test':2}}})
console.log(t);

function merge(...args) {
  return Object.assign({}, ...args);
}
avatar
Force Bolt
25 мая 2021 в 18:43
0

Попробуйте этот способ, используя библиотеку jQuery

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

console.log(jQuery.extend(obj1, obj2))
avatar
space97
18 марта 2021 в 14:28
5

Похоже, это должно быть все, что вам нужно:

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

var obj3 = { ...obj1, ...obj2 }

После этого obj3 должен иметь следующее значение:

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

Попробуйте здесь:

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

var obj3 = { ...obj1, ...obj2 }

console.log(obj3);
avatar
11 февраля 2021 в 11:20
1

Это можно сделать тремя способами: -

Подход 1: -

// using spread ...
    let obj1 = {
        ...obj2
    };

Подход 2: -

// using  Object.assign() method
let obj1 = Object.assign({}, obj2);

Подход 3: -

// using JSON
let obj1 = JSON.parse(JSON.stringify(obj2));
avatar
20 октября 2020 в 05:13
2
Object.assign(TargetObject, Obj1, Obj2, ...);
avatar
6 октября 2020 в 09:42
1

Есть разные способы добиться этого:

Object.assign(targetObj, sourceObj);

targetObj = {...targetObj, ...sourceObj};
avatar
Jaime Asm
16 сентября 2020 в 20:23
58

Для этого можно использовать синтаксис расширения объекта. Это часть ES2018 и не только.

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

const obj3 = { ...obj1, ...obj2 };
console.log(obj3);
Slava
11 октября 2017 в 10:01
0

Поддержка браузера?

connexo
2 января 2018 в 10:32
1

@ Alph.Dev Вы знаете caniuse.com?

klewis
16 марта 2018 в 19:52
1

Я не могу заставить работать трехточечный синтаксис в node.js. узел жалуется на это.

avatar
Kavale arun
16 сентября 2020 в 20:13
3

Вы можете использовать метод Object.assign. Например:

var result = Object.assign(obj1, obj2);

Также обратите внимание, что он создает неглубокую копию объекта.

avatar
Logan
25 августа 2020 в 17:01
12

Вау ... это первая публикация на StackOverflow, которую я видел с несколькими страницами. Приносим извинения за добавление еще одного "ответа"


ES5 и более ранние версии

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

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

function extend() {
    for (var o = {}, i = 0; i < arguments.length; i++) {
        // Uncomment to skip arguments that are not objects (to prevent errors)
        // 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 objects
 */
function extend() {
    for (var o = {}, i = 0; i < arguments.length; i++) {
        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;
}

/**
 * Example
 */
document.write(JSON.stringify(extend({
    api: 1,
    params: {
        query: 'hello'
    }
}, {
    params: {
        query: 'there'
    }
})));
// outputs {"api": 1, "params": {"query": "there"}}

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

avatar
Eugene Tiurin
20 июня 2020 в 09:12
43

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

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

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

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

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

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

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

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

        var keysArray = Object.keys(nextSource);
        for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
          var nextKey = keysArray[nextIndex];
          var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
          if (desc !== undefined && desc.enumerable) {
            to[nextKey] = nextSource[nextKey];
          }
        }
      }
      return to;
    }
  });
}
avatar
11 января 2020 в 12:59
4

Используйте оператор Spread, который следует за версией ES6

var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog' }
let result = {...obj1,...obj2};
console.log(result)

output { food: 'pizza', car: 'ford', animal: 'dog' }
avatar
23 декабря 2019 в 08:03
2

неглубокий

var obj = { name : "Jacob" , address : ["America"] }
var obj2 = { name : "Shaun" , address : ["Honk Kong"] }

var merged = Object.assign({} , obj,obj2 ); //shallow merge 
obj2.address[0] = "new city"

result.address [0] изменен на «новый город», т.е. объединенный объект также изменится. Это проблема неглубокого слияния.

глубокий

var obj = { name : "Jacob" , address : ["America"] }
var obj2 = { name : "Shaun" , address : ["Honk Kong"] }

var result = Object.assign({} , JSON.parse(JSON.stringify(obj)),JSON.parse(JSON.stringify(obj2)) )

obj2.address[0] = "new city"

адрес результата [0] не изменился

GroovyDotCom
16 ноября 2020 в 20:32
0

var merged = Object.assign ({}, obj, obj2) ничего не объединяет?

avatar
14 октября 2019 в 05:13
1

объединить два объекта с помощью Object.assign и оператора распространения.

Неправильный путь (изменить исходный объект из-за таргетинга o1)

var o1 = { X: 10 };
var o2 = { Y: 20 };
var o3 = { Z: 30 };
var merge = Object.assign(o1, o2, o3);
console.log(merge)  // {X:10, Y:20, Z:30}
console.log(o1)     // {X:10, Y:20, Z:30}

Правильно

  • Object.assign ({}, o1, o2, o3) ==> таргетинг на новый объект

  • {... o1, ... o2, ... o3} ==> распространение объектов

var o1 = { X: 10 };
var o2 = { Y: 20 };
var o3 = { Z: 30 };

console.log('Does not modify original objects because target {}');
var merge = Object.assign({}, o1, o2, o3);
console.log(merge); // { X: 10, Y: 20, Z: 30 }
console.log(o1)

console.log('Does not modify original objects')
var spreadMerge = {...o1, ...o2, ...o3};
console.log(spreadMerge);
console.log(o1);
avatar
Legends
30 августа 2019 в 11:49
13

** Объединить объекты просто с помощью оператора Object.assign или расширения ... **

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


var mergedObj = Object.assign(obj1,obj2,obj3)
 // or using the Spread operator (...)
var mergedObj = {...obj1,...obj2,...obj3}

console.log(mergedObj);

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

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

avatar
Bekim Bacaj
16 апреля 2019 в 19:58
1

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

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

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

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

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

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

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

;
var obj1 = {a:1}, obj2 = {b:2}, obj3 = {c:3}
;
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() +"}" );
    }
;
var master = Merge( obj1, obj2, obj3 )
;
console.log( JSON.stringify( master ) )
;
avatar
14 марта 2019 в 06:55
4

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
  })
}
Chris Stryczynski
4 апреля 2019 в 11:54
1

Кажется, это не работает? typescript-play.js.org/#code/…

avatar
17 января 2019 в 11:30
5

let obj1 = {a:1, b:2};
let obj2 = {c:3, d:4};
let merged = {...obj1, ...obj2};
console.log(merged);
avatar
7 ноября 2018 в 13:16
1

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

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 }

Это обычно полезно при объединении dict параметров с настройками по умолчанию в функции или плагине.

Если поддержка IE 8 не требуется, вы можете вместо этого использовать Object.keys для тех же функций:

function extend(obj, src) {
    Object.keys(src).forEach(function(key) { obj[key] = src[key]; });
    return obj;
}

Это требует немного меньше кода и немного быстрее.

avatar
18 сентября 2018 в 01:55
8
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"}
avatar
Avdi
19 июля 2018 в 18:28
1216

В 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.
webmat
4 мая 2011 в 16:01
169

Осторожно: переменная "settings" все же будет изменена. jQuery не возвращает новый экземпляр. Причина этого (и именования) в том, что .extend () был разработан для расширения объектов, а не для объединения вещей вместе. Если вам нужен новый объект (например, настройки по умолчанию, которые вы не хотите трогать), вы всегда можете jQuery.extend ({}, settings, options);

vol7ron
9 июня 2011 в 21:09
28

Имейте в виду, что jQuery.extend также имеет глубокую (логическую) настройку. jQuery.extend(true,settings,override), что важно, если свойство в настройках содержит объект, а переопределение имеет только часть этого объекта. Вместо удаления несогласованных свойств, глубокая настройка будет обновляться только там, где она существует. По умолчанию - false.

avatar
vsync
17 июня 2018 в 12:19
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 )
pancake
24 апреля 2012 в 05:02
4

Это не сработает, если o2 содержит какие-либо свойства, которых еще нет в o1, именно поэтому у Маркуса есть команда try / catch, которую вы удалили. Ваш пример работает только потому, что все свойства o2 уже существуют в o1. Итак, это не слияние, и это не лучше!

vsync
3 сентября 2013 в 12:16
0

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

mindplay.dk
4 апреля 2016 в 15:51
0

Следует отметить, что функция является деструктивной и obj1 , а также любые объекты, вложенные в нее, будут изменены, что может или не может быть тем, что вы хотели. Для ясности я сам переименовал функцию и аргументы в applyProperties(target, source).

vsync
4 апреля 2016 в 18:06
0

@ mindplay.dk - что ты имеешь в виду деструктивный ? Дело в том, чтобы объединить o2 в o1, а не создавать новый (третий) объект o1, объединенный с o2. Я ответил на точный вопрос

mindplay.dk
9 апреля 2016 в 14:48
0

@vsync деструктивен в том смысле, что, например, Array.sort () деструктивен, а Array.slice () - нет - это не критика, просто указание на факт :-)

vsync
9 апреля 2016 в 16:01
0

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

avatar
31 мая 2018 в 13:11
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)
avatar
Snoozer Man
6 ноября 2017 в 21:27
7

Основываясь на ответах Маркуса и vsync, это расширенная версия. Функция принимает любое количество аргументов. Его можно использовать для установки свойств на узлах 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 (включая null), будет проигнорирован. За исключением первого аргумента, также отбрасываются узлы 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;
}
avatar
Algy
28 октября 2017 в 12:31
20

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

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

avatar
gossi
23 мая 2017 в 12:26
11

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

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

Если переопределение имеет значение 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

avatar
24 апреля 2017 в 18:29
1

Встроенный однострочник, совместимый с ES5:

var merged = [obj1, obj2].reduce(function(a, o) { for(k in o) a[k] = o[k]; return a; }, {})
avatar
Paul Spaulding
18 апреля 2017 в 10:21
29

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

  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
    };
*/
avatar
mitch3ls
2 февраля 2017 в 14:27
-2

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

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

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

const objB = {
  attrC: 2
}

const mergedObj = {...objA, ...objB}
Michał Perłakowski
2 февраля 2017 в 13:09
0

Свойства распространения объекта не являются частью ES2016 - это предложение стадии 3. Кроме того, это уже было рассмотрено в этом ответе.

avatar
31 декабря 2016 в 11:04
-2

Если вам нужно глубокое слияние, которое также будет «объединять» массивы, объединяя их в результате, тогда эта функция 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; }

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

avatar
Nishant
25 октября 2016 в 22:06
0

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

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";
  }
}
avatar
Developerrr
25 октября 2016 в 22:03
0

Если вы используете 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 .

avatar
Etherealone
25 октября 2016 в 22:01
2

Я использую следующее, написанное на чистом 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];
      }
    }
  }
};
avatar
Tazo Todua
25 октября 2016 в 21:59
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);
}
avatar
appsmatics
25 октября 2016 в 21:58
36

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

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

>
avatar
Peter Mortensen
25 октября 2016 в 21:56
18

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

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

avatar
jamesmstone
25 октября 2016 в 21:54
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.
ItalyPaleAle
29 апреля 2014 в 20:34
1

Это не встроенная библиотека, это модуль NPM.

avatar
devmao
25 октября 2016 в 21:53
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}
avatar
AndreasE
25 октября 2016 в 21:52
84

Подобно 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);
avatar
Paul
25 октября 2016 в 21:51
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();
avatar
pagid
25 октября 2016 в 21:45
4

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

avatar
Andreas Linden
25 октября 2016 в 21:43
30

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

Вот как действительно слилась область объектов 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);
avatar
orian
25 октября 2016 в 21:40
12

На всякий случай, если кто-то использует Библиотеку закрытия Google:

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'
avatar
Industrial
25 октября 2016 в 21:39
179

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

_.extend({name : 'moe'}, {age : 50});
=> {name : 'moe', age : 50}
Abe Voelker
5 июня 2012 в 18:12
38

Этот пример хорош, поскольку вы имеете дело с анонимными объектами, но если это не так, тогда комментарий webmat в ответе jQuery предупреждение о мутациях применяется здесь, поскольку подчеркивание также изменяет целевой объект. Как и ответ jQuery, чтобы сделать это без мутаций, просто слейтесь с пустым объектом: _({}).extend(obj1, obj2);

avatar
Prabhakar Kasi
25 октября 2016 в 21:38
1

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

Y.merge(obj1, obj2, obj3....) 
avatar
Emre Erkan
25 октября 2016 в 21:24
67

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

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 }));
avatar
25 октября 2016 в 21:21
2

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

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

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

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

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

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

avatar
Mark
25 октября 2016 в 20:40
9

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

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

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

См. слияние (объект): Объект .

avatar
RobKohr
25 октября 2016 в 20:37
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 }
avatar
antony
25 октября 2016 в 20:36
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;
}
avatar
philfreo
25 октября 2016 в 20:29
10

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

Object.merge(obj1, obj2);
avatar
25 октября 2016 в 20:28
1

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

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

obj1 = Object.extend(obj1, obj2);
avatar
ephemient
25 октября 2016 в 20:26
15

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

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

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

avatar
NanoWizard
8 августа 2016 в 19:12
369

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

Object.assign(obj1, obj2);

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

Joachim Lous
16 марта 2016 в 10:04
39

Обратите внимание, что это только неглубокое слияние

brass monkey
26 мая 2016 в 15:38
0

Я думаю, что тем временем Object.assign имеет довольно приличный охват: kangax.github.io/compat-table/es6/…

Duvrai
21 июля 2016 в 20:02
13

Теперь это должен быть правильный ответ. В настоящее время люди компилируют свой код для совместимости с редким браузером (IE11), который не поддерживает такого рода вещи. Боковое примечание: если вы не хотите добавлять obj2 в obj1, вы можете вернуть новый объект, используя Object.assign({}, obj1, obj2)

NanoWizard
8 августа 2016 в 19:15
6

@Duvrai Согласно отчетам, которые я видел, IE11 определенно не редкость, составляя около 18% доли рынка по состоянию на июль 2016 года.

avatar
Dinusha
1 марта 2016 в 10:49
16

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

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

jQuery.extend(obj1, obj2);

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

avatar
30 декабря 2015 в 16:40
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 выдаст 'ошибку'

avatar
22 декабря 2015 в 11:02
5

Вы должны использовать lodash по умолчаниюDeep

_.defaultsDeep({ 'user': { 'name': 'barney' } }, { 'user': { 'name': 'fred', 'age': 36 } });
// → { 'user': { 'name': 'barney', 'age': 36 } }
avatar
16 ноября 2015 в 16:35
20

Назначение объекта()

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.
avatar
Sherali Turdiyev
14 октября 2015 в 10:30
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 {};
}
avatar
14 октября 2014 в 12:33
0

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

Кроме того, это рекурсивный , и вы можете выбрать, хотите, чтобы перезаписать значения и <866928890> 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}

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

avatar
6 декабря 2013 в 11:41
1

Я использовал 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 перед объединением, чтобы избежать дублирования.

avatar
1 августа 2013 в 16:03
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;
}

:)

avatar
9 мая 2013 в 15:16
281

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

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

Код

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

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

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

      }

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

    }
  }

  return obj1;
}

Пример

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

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

o3 = MergeRecursive(o1, o2);

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

o3 = {  a : 10,
        b : 2,
        c : {
          ca : 10,
          cb : 20,
          cc : { 
            cca : 101,
            ccb : 202 } } };
skerit
16 января 2011 в 16:00
11

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

avatar
19 декабря 2012 в 17:39
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 ()}

jleviaguirre
19 декабря 2012 в 17:41
0

кстати, в dojo есть функция под названием mixin, поэтому dojo.mixin (A, B) сделает свое дело

avatar
1 октября 2012 в 08:31
0

Это объединяет 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}}
avatar
20 июля 2012 в 22:42
-1
function extend()
{ 
    var o = {}; 

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

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

    return o;
}
avatar
9 ноября 2010 в 22:09
17

Лучший способ сделать это - добавить правильное свойство, которое нельзя перечислить, с помощью 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/exnding-objects-in-node-js

avatar
21 декабря 2008 в 13:29
42

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