Як дублювати властивості об’єкта в іншому об’єкті?


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?



1
Питання в тому, чи хочете ви дрібну чи глибоку копію? Якщо глибоко, як глибоко?
georg

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, я не Ігор Попов ;-) І будучи не ОП, я вже сказав, що вважаю вказівник корисним, і ваша відповідь теж є, що мені не подобається частина "ви справді повинні використовувати".
Майкл Крелін - хакер

23
Ви пропускаєте hasOwnProperty()тест, і справи продовжують працювати. Поки вони не зупиняться, адже ваші предмети з часом стали складнішими. За винятком того, що вона таємниче розбивається на незв'язану частину коду, оскільки було скопійовано занадто багато. І у вас немає жодного контексту для налагодження. JS відсмоктує так, тому ретельне кодування для запобігання виникнення подібних проблем є доцільним.
Елі Бендерський

2
Я думаю, що цю відповідь потрібно оновити відповідно до наступного посилання developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… const target = {a: 1, b: 2}; джерело const = {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}
Elbassel

170

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

Використання просте:

Object.assign(secondObject, firstObject);

Це воно!

Підтримка зараз очевидно погана; лише Firefox (34+) підтримує його поза програмою, тоді як Chrome (45+) та Opera (32+) вимагають встановити "експериментальний прапор".

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


4
+1, ще одна цікава функція ES6. Звичайно, на сьогодні бракує браузера / навіть підтримки Node.JS, але, як ви вже згадували, є транспілери. А якщо вони вам не подобаються - shims: github.com/paulmillr/es6-shim (або автономний, Object.assign()-onim shim: github.com/ljharb/object.assign ).
бардусний

1
@Xoyce Якщо ви перевірите пов’язану сторінку MDN, вона чітко зазначає "Якщо значення джерела є посиланням на об'єкт, воно лише копіює це посилання". Таким чином, він дійсно зберігає посилання і не копіює об'єкт. Ваше попередження проти несподіваної поведінки все ще влучно, і воно зводиться до того, щоб мати належні очікування.
Жниварка DIMM

@mostafiz Я відмовив ваше редагування, тому що питання та інші відповіді на цій сторінці використовують назви "firstObject" та "secondObject", тому для чіткості та послідовності я тут використовував ті самі назви.
Жниварка DIMM

Якщо це відповідає питанню, то це добре.
Мостафіз Рахман


101

За ES6 - синтаксис поширення :

Ви можете просто використовувати:

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

Це дозволяє уникнути проблем передачі цих об'єктів посиланням.

Крім того, вона опікується предметами, які мають глибоке гніздування.


2
Ого, це справді дивовижно :) Дякую за відповідь. Очевидно, мені це вже не потрібно (оскільки це було давно), але це може допомогти комусь іншому.
Ігор Попов

1
+1 для ще більш крутого використання ES6! Документи MDN, на які згадувалося вище, не згадують використання оператора розповсюдження на об'єктах, тому я склав загадку,
DIMM Reaper

1
@jaepage - хороший коментар для довідки. Об'єкт (за оригінальним запитанням) з простими назвами властивостей є ітерабельним.
kingPuppy

1
Працює в Chrome, це ES6, вам зараз знадобиться Babel або якийсь трансформатор ES6. В майбутньому очікується, що весь браузер підтримуватиме цей синтаксис.
король Щеня

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-shim для цих старовинних браузерів доступний , який поліфікує багато функцій ES5 (включаючи ці два).

(Я весь для поліфілів, на відміну від того, щоб стримувати використання класних, нових мовних функцій.)


Раптом 2 низовини з нізвідки. Роблячи невеликі шанси, що ці хлопці прочитають цей коментар - у чому їх справжня причина? Що б ви запропонували змінити / покращити у своїй відповіді?
бардусний

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

Зауважте, що це не глибоко копіює масиви та не функціонує об'єкти (але він робить глибоку копію всіх інших видів об'єктів).
Метт Браун

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.
Yetti99

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


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;
}, {});

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. org / en-US / docs / Web / JavaScript / Довідка / Global_Objects / Object / create

Ви також можете просто призначити значення та опустити дескриптори та зробити їх трохи коротшими:

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

Використання методу follwing скопіює властивості

secondObject.copy(firstObject)

Я дуже новачок у JavaScript, але вважаю, що це працює. Я думаю, занадто довго, але це працює.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.