2013-12-15 5 views
6

У меня есть defaultObject подобное:Слияние двух объектов без переопределения

var default = { 
    abc: "123", 
    def: "456", 
    ghi: { 
     jkl: "789", 
     mno: "012" 
    } 
}; 

И у меня еще вроде:

var values = { 
    abc: "zzz", 
    ghi: { 
     jkl: "yyy", 
    } 
}; 

Как я могу объединить эти 2 объекта со следующим результатом (без переопределения) ?

var values = { 
    abc: "zzz", 
    def: "456", 
    ghi: { 
     jkl: "yyy", 
     mno: "012" 
    } 
}; 

(я не хочу, чтобы изменить объект по умолчанию!)

ответ

5

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

var temp = {}; 
$.extend(true, temp, _default, values); 
values = temp; 

Обратите внимание, что default является зарезервированным ключевым словом, и не может быть использован в качестве имя переменной

+0

Но это изменится «default_array» мой по умолчанию, и я не хочу, потому что это глобальная переменная ... – amp

+2

@amp - это легко избегать использования временного объекта. – adeneo

+0

Не могу поверить! Так очевидное решение ... – amp

6

Для тех, кто не использует jQuery, здесь идет решение vanilla-js.

Решение:

function extend (target) { 
    for(var i=1; i<arguments.length; ++i) { 
     var from = arguments[i]; 
     if(typeof from !== 'object') continue; 
     for(var j in from) { 
      if(from.hasOwnProperty(j)) { 
       target[j] = typeof from[j]==='object' 
       ? extend({}, target[j], from[j]) 
       : from[j]; 
      } 
     } 
    } 
    return target; 
} 

СжатыйClosure Compiler):

только 199 символов!

var extend=function e(c){for(var d=1;d<arguments.length;++d){var a=arguments[d];if("object"===typeof a)for(var b in a)a.hasOwnProperty(b)&&(c[b]="object"===typeof a[b]?e({},c[b],a[b]):a[b])}return c} 

Как использовать:

extend(target, obj1, obj2); // returns target 

Если вы только хотите объединить, используйте

var merged = extend({}, obj1, obj2); 

Особенности:

  • Он не смотрит на прототип объектов.
  • Игнорирует не объекты.
  • Рекурсивный, чтобы объединить свойства, являющиеся объектами.
  • Объекты, на которые ссылаются объекты target, если они расширены, заменяются новыми, а оригинальные не изменяются.
  • В случае одинаковых имен свойств объединенное значение будет состоять из объединения объектов после последнего (в порядке аргументов) значения, отличного от объекта. Или, если последний не является объектом, сам.

Примеры:

extend({}, {a:1}, {a:2});   // {a:2} 
extend({}, {a:1}, {b:2});   // {a:1, b:2} 
extend({}, {a: {b:1}}, {a: {b:2}}); // {a: {b:2}} 
extend({}, {a: {b:1}}, {a: {c:2}}); // {a: {b:2, c:2}} 
extend({}, {a: {a:1}}, {a: {b:2}}, {a: 'whatever non object'}); 
    // {a: "whatever non object"} 
extend({}, {a: {a:1}}, {a: {b:2}}, {a: 'whatever non object'}, {a: {c:3}},{a: {d:4}}); 
    // {a: {c:3, d:4}} 

Предупреждение:

Имейте в виду, что если браузер не достаточно умен, он может оказаться в ловушке в бесконечном цикле:

var obj1={}, 
    obj2={}; 
obj1.me=obj1; 
obj2.me=obj2; 
extend({},obj1,obj2); 

Если браузер достаточно умен, он может t забросить ошибку или вернуть {me: undefined} или что угодно.

Обратите внимание, что это предупреждение также применяется, если вы используете jQuery's $.extend.

1

Другим способом было бы просто расширить значение по умолчанию (вместо другого пути вокруг которого будет переопределить значение по умолчанию)

Object.assign(value, default) // values of default overrides value 
default = value // reset default to value 

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

0

Кроме того, если вы счастливы с ES6:

Object.assign({}, default, values) 
Смежные вопросы