Как дублировать свойства объекта в другом объекте?

185

Учитывая объект:

var firstObject = {
    key1 : 'value1',
    key2 : 'value2'
};

Как я могу скопировать свойства внутри другого объекта ( secondObject), как это:

var secondObject = {
    key1 : 'value1',
    key2 : 'value2',
    key3 : 'value3',
    key4 : 'value4'
};

используя ссылку на firstObject? Что-то вроде этого:

var secondObject = {
    firstObject,
    key3 : 'value3',
    key4 : 'value4'
};

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

Возможно ли решение без использования JavaScript-фреймворков?

Игорь Попов
источник
3
Ответили здесь: stackoverflow.com/questions/171251/…
Calvin
1
Вопрос в том, хотите ли вы неглубокую или глубокую копию? Если глубоко, как глубоко?
Георг
5
FWIW, они называются «свойствами», а не «атрибутами».
TJ Crowder
Вот кое-что действительно уродливое, которое работает тем не менее (фактически не рекомендуется! Только однострочное подтверждение концепции):secondObject = JSON.parse('{' + JSON.stringify(firstObject).match(/^.(.*).$/)[1] + ',' + JSON.stringify(secondObject).match(/^.(.*).$/)[1] + '}');
Бен Ли
@TJCrowder: я исправил вопрос ... спасибо.
Игорь Попов

Ответы:

213
for(var k in firstObject) secondObject[k]=firstObject[k];
Михаил Крелин - хакер
источник
3
@BenLee, здесь вам не хватает того, что Игорь показал, какое именно использование он использует для этого, что hasOwnPropertyбесполезно. Хотя я нахожу ваш указатель полезным, я считаю идею применения любых правил к любой ситуации вредной и неразумной. Как и все эти практики разработки, основанные на шаблонах, так что не воспринимайте это как личность ...
Майкл Крелин - хакер
1
@ MichaelKrelin-хакер, чего вам здесь не хватает, так это того, что StackOverflow предназначен не только для использования ОП. Он используется в качестве справки для будущих посетителей, которые могут иметь несколько разные варианты использования, где этот указатель может быть полезен.
Бен Ли
@BenLee, я не IgorPopov ;-) И, будучи не ОП, я уже сказал, что нахожу указатель полезным, и ваш ответ тоже, мне не нравится часть «Вы должны действительно использовать».
Майкл Крелин - хакер
23
Вы пропускаете hasOwnProperty()тест, и все вроде как работает. Пока они не остановятся, потому что ваши объекты со временем стали более сложными. За исключением этого, он таинственным образом ломается в несвязанной части кода, потому что слишком много было скопировано. И у вас нет контекста для отладки. JS такой отстой, поэтому осторожное кодирование, чтобы предотвратить возникновение таких проблем, является благоразумным.
Эли Бендерский
2
Я думаю, что этот ответ необходимо обновить по следующей ссылке developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… const target = {a: 1, b: 2}; постоянный источник = {b: 4, c: 5}; const returnTarget = Object.assign (цель, источник); console.log (цель); // ожидаемый результат: Object {a: 1, b: 4, c: 5} console.log (returnTarget); // ожидаемый результат: Объект {a: 1, b: 4, c: 5}
Эльбассель
170

Пользуясь ответом @ Bardzuśny здесь, ES6 предоставила собственное решение: Object.assign()функцию!

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

Object.assign(secondObject, firstObject);

Это оно!

Поддержка сейчас явно плохая; только Firefox (34+) поддерживает его "из коробки", в то время как Chrome (45+) и Opera (32+) требуют установки «экспериментального флага».

Поддержка улучшается, и ее поддерживают последние версии Chrome, Firefox, Opera, Safari и Edge (IE, в частности, не имеет поддержки). Также доступны транспортеры, такие как Babel и Traceur. Смотрите здесь для более подробной информации.

Жнец DIMM
источник
4
+1, еще одна классная особенность ES6. Конечно, поддержка браузера / даже Node.JS пока отсутствует, но, как вы упомянули, есть доступные транспортеры. А если они вам не нравятся - shims: github.com/paulmillr/es6-shim (или автономно, только Object.assign()shim: github.com/ljharb/object.assign ).
Бардзусный
1
@Xoyce Если вы проверяете связанную страницу MDN, она четко заявляет: «Если исходное значение является ссылкой на объект, оно только копирует это ссылочное значение». Таким образом, он действительно сохраняет ссылку и не копирует объект. Ваше предупреждение против неожиданного поведения все еще уместно, и оно сводится к тому, чтобы иметь надлежащие ожидания.
Жнец DIMM
@mostafiz Я откатил ваши правки, потому что вопрос и другие ответы на этой странице используют имена «firstObject» и «secondObject», поэтому я использовал эти же имена здесь для ясности и последовательности.
Жнец DIMM
Если это согласуется с вопросом, тогда все в порядке.
Мостафиз Рахман
1
@pdem Да - смотрите ответ kingPuppy .
Жнец DIMM
101

Согласно ES6 - Синтаксис распространения :

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

const thirdObject = {
   ...firstObject,
   ...secondObject   
}

Это позволяет избежать проблем передачи этих объектов по ссылке.

Кроме того, он заботится об объектах, которые имеют глубокое вложение.

kingPuppy
источник
2
Вау, это действительно круто :) Спасибо за ответ. Очевидно, мне это больше не нужно (так как это было давно), но это может помочь кому-то еще.
Игорь Попов
1
+1 для еще более прохладного использования ES6! В документах MDN, упомянутых выше, не упоминается использование оператора распространения для объектов, поэтому я сделал скрипку, чтобы увидеть его в действии: es6fiddle.net/im3ifsg0
Жнец DIMM
1
@jaepage - хороший комментарий для справки. Объект (согласно исходному вопросу) с простыми именами свойств является итеративным.
kingPuppy
1
Работает в Chrome, это ES6, сейчас вам понадобится Babel или какой-нибудь транспортер ES6. Ожидается, что в будущем все браузеры будут поддерживать этот синтаксис.
kingPuppy
89

Просмотрите свойства первого объекта и назначьте их второму объекту, например так:

var firstObject = {
    key1 : 'value1',
    key2 : 'value2'
};

var secondObject = {
    key3 : 'value3',
    key4 : 'value4'
};

for (var prop in firstObject) {
    if (firstObject.hasOwnProperty(prop)) {
        secondObject[prop] = firstObject[prop];
    }
}

for- inпетля не достаточно; вам нужно hasOwnProperty. См. Http://bonsaiden.github.com/JavaScript-Garden/#object.forinloop для подробного объяснения причин.

Бен Ли
источник
@RobW, я не думал, что ОП использует referenceтехнический смысл. Я думаю, что он просто имеет в виду естественный язык «ссылаясь на».
Бен Ли
1
@RobW: ОП на самом деле сказал «копировать».
TJ Crowder
49

Здесь играют некроманта, потому что ES5 принес нам Object.keys(), с потенциалом, чтобы спасти нас от всех этих .hasOwnProperty()проверок.

Object.keys(firstObject).forEach(function(key) {
  secondObject[key] = firstObject[key];
});

Или, оборачивая это в функцию (ограниченная «копия» lodash _.assign()):

function assign(object, source) {
  Object.keys(source).forEach(function(key) {
    object[key] = source[key];
  });
}

assign(secondObject, firstObject); // assign firstObject properties to secondObject

Object.keys()это относительно новый метод, в частности: недоступен в IE <9. То же самое на самом деле касается .forEach()метода массива, который я использовал вместо обычного forцикла.

К счастью, есть ES5-прокладка для этих древних браузеров, которые будут polyfill много возможностей ES5 ( в том числе два).

(Я полностью за полифиллы, а не за то, чтобы не использовать классные новые языковые функции.)

bardzusny
источник
Внезапно, 2 downvotes из ниоткуда. Вероятность того, что эти парни прочтут этот комментарий, невелика - в чем их причина? Что бы вы предложили изменить / улучшить в моем ответе?
Бардзусны
1
Это определенно заслуживает того, чтобы подняться на вершину, а также инициализатора распространения объекта вниз (ES6) - это выглядит еще чище с функциями стрелок!
mjohnsonengr
12

Это необходимо, чтобы люди могли найти метод глубокого копирования с hasOwnProperty и фактической проверкой объекта:

var extend = function (original, context, key) {
  for (key in context)
    if (context.hasOwnProperty(key))
      if (Object.prototype.toString.call(context[key]) === '[object Object]')
        original[key] = extend(original[key] || {}, context[key]);
      else
        original[key] = context[key];
  return original;
};
Nijikokun
источник
Обратите внимание, что это не глубокое копирование массивов или функциональных объектов (но это делает глубокое копирование всех других типов объектов).
Мэтт Браун
1
Да, если вы хотите глубоко копировать массивы, просто измените проверку типа, чтобы включить'[object Array]'
Nijikokun
12

Можно использовать Object.assign для объединения объектов. Он объединяет и переопределяет общее свойство справа налево, т. Е. То же свойство слева будет переопределено справа.

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

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

var firstObject = {
    key1 : 'value1',
    key2 : 'value2'
};

var secondObject = {
    key3 : 'value3',
    key4 : 'value4'
};

var finalObject = Object.assign({}, firstObject, secondObject)

console.log(finalObject)

Пранеш Рави
источник
но что, если вы хотите, чтобы он мутировал первый объект? У вас есть объект A и объект B, и вы хотите, чтобы он мутировал объект A так, чтобы все свойства были такими же, как у объекта B? Вы бы сделали Object.assign (A, B)?
TKoL
К сожалению, не поддерживается в IE, Android WebView, Android Opera в соответствии с этой страницей Mozilla Developer Network.
Йетиti
6

Улучшение идеи kingPuppy и идеи OP (мелкая копия) - я добавляю только 3 точки к OP-примеру :)

var secondObject = {
    ...firstObject,
    key3 : 'value3',
    key4 : 'value4'
};

Камил Келчевски
источник
4

Это должно работать, проверено здесь .

var secondObject = {
    firstObject: JSON.parse(JSON.stringify(firstObject)),
    key3 : 'value3',
    key4 : 'value4'
};

Примечание . Это не приведет к копированию методов firstObject
примечания 2 : для использования в более старых браузерах вам потребуется анализатор json.
Примечание 3 : назначение по ссылке является жизнеспособным вариантом, особенно если он firstObjectсодержит методы. Скорректировал данный пример jsfiddle соответственно

KooiInc
источник
3

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

function extend( obj1, obj2 ) {
    for ( var i in obj2 ) {
        obj1[i] = obj2[i];
    }
    return obj1;
}

var firstObject = {
    key1: "value1",
    key2: "value2"
};

var secondObject = extend({
    key3: "value3",
    key4: "value4"
}, firstObject );
Будет
источник
Это также скопирует нативные свойства. А как насчет свойств, которые сами объекты?
KooiInc
1

Если вы хотите получить только те свойства, которые существуют во втором объекте, вы можете использовать, Object.keysчтобы получить свойства первого объекта, вы можете сделать два метода:

A.) map назначить свойства первого объекта второму объекту, используя побочные эффекты:

var a = {a:100, b:9000, c:300};
var b = {b:-1};

Object.keys(a).map(function(key, index) {
    if (typeof b[key] !== 'undefined') {
        console.log(key);
        b[key] = a[key];    
    }
});

Б.) или reduceсоздать новый объект и назначить его второму объекту. Имейте в виду, что этот метод заменяет другие свойства, которые второй объект мог иметь до того, который не соответствовал первому объекту:

var a = {a:100, b:9000, c:300};
var b = {b:-1, d:-1}; // d will be gone

b = Object.keys(a).reduce(function(result, current) {
    if (typeof b[current] !== 'undefined') {
        result[current] = a[current];   
    }
    return result;
}, {});
apebeast
источник
1

Используйте нотацию распространения собственности. Он был добавлен в ES2018 (распространение для массивов / итераций было ранее, ES2015), {... firstObject} распространяет все перечисляемые свойства как дискретные свойства.

let secondObject = {
      ...firstObject,
      key3 : 'value3',
      key4 : 'value4'
    }
Энтони Оулей
источник
Можете ли вы дать некоторое представление о вашем ответе и о том, почему он решает данный вопрос
Тамир Кляйн
0

Я бы предпочел использовать firstObject в качестве прототипа secondObject и добавить дескриптор свойства:

var secondObject = Object.create(firstObject, {
      key3: {value: "value3", writable: true, configurable: true, enumerable: true},
      key4: {value: "value4", writable: true, configurable: true, enumerable: true}
      });

Это, конечно, не одна строка, но это дает вам больше контроля. Если вас интересуют дескрипторы свойств, я предлагаю прочитать эту статью: http://patrickdelancy.com/2012/09/property-descriptors-in-javascript/#comment-2062 и страницу MDN https: //developer.mozilla. орг / EN-US / Docs / Web / JavaScript / Справка / Global_Objects / Объект / создать

Вы также можете просто присвоить значения и опустить дескрипторы и сделать его немного короче:

var secondObject = Object.create(firstObject, {
      key3: {value: "value3"}
      key4: {value: "value4"}
  });

Совместимость: ECMAScript 5, поэтому IE9 +

Ахмет Цетин
источник
0
var firstObject = {
     key1: "value1",
     key2: "value2"
};

var secondObject = {
     key3: "value3",
     key4: "value4"
     copy: function(firstObject){
           this.key1 = firstObject.key1;
           this.key2 = firstObject.key2;
     }
 };

Использование следующего метода скопирует свойства

secondObject.copy(firstObject)

Я очень новичок в JavaScript, но нашел, что это работает. Наверное, слишком долго, но это работает.

Синдху Тирт
источник