Bagaimana cara menduplikasi properti objek di objek lain?

185

Diberikan objek:

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

bagaimana cara menyalin properti di dalam objek lain ( secondObject) seperti ini:

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

menggunakan referensi ke firstObject? Sesuatu seperti ini:

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

(Ini tidak berfungsi ... Saya hanya menunjukkan pada garis besar bagaimana saya ingin menyusun kode).

Apakah solusi mungkin tanpa menggunakan kerangka kerja JavaScript?

Igor Popov
sumber
3
Dijawab di sini: stackoverflow.com/questions/171251/…
Calvin
1
Pertanyaannya adalah, apakah Anda menginginkan salinan yang dangkal atau dalam? Jika dalam, seberapa dalam?
georg
5
FWIW, mereka disebut "properti," bukan "atribut."
TJ Crowder
Berikut ini adalah sesuatu yang sangat jelek yang bekerja (tidak benar-benar direkomendasikan! Hanya pembuktian konsep satu-liner):secondObject = JSON.parse('{' + JSON.stringify(firstObject).match(/^.(.*).$/)[1] + ',' + JSON.stringify(secondObject).match(/^.(.*).$/)[1] + '}');
Ben Lee
@TJCrowder: Saya mengoreksi pertanyaan ... terima kasih.
Igor Popov

Jawaban:

213
for(var k in firstObject) secondObject[k]=firstObject[k];
Michael Krelin - hacker
sumber
3
@ BenLee, apa yang Anda lewatkan di sini adalah bahwa Igor telah menunjukkan penggunaan yang tepat untuknya, yang hasOwnPropertytidak berguna. Sementara saya menemukan pointer Anda bermanfaat, saya menganggap gagasan menerapkan setiap aturan untuk setiap situasi yang berbahaya dan tidak bijaksana. Seperti semua praktik pengembangan berbasis pola yang sedang terjadi, jadi jangan menganggapnya pribadi ...
Michael Krelin - hacker
1
@ MichaelKrelin-hacker, yang Anda lewatkan di sini adalah bahwa StackOverflow tidak hanya untuk kepentingan OP. Ini digunakan sebagai referensi untuk pengunjung masa depan yang mungkin memiliki kasus penggunaan yang sedikit berbeda, di mana pointer itu mungkin berguna.
Ben Lee
@ BenLee, saya bukan IgorPopov ;-) Dan bukan OP, saya sudah mengatakan bahwa saya menemukan pointer berguna dan jawaban Anda juga, itu adalah bagian "Anda benar-benar harus menggunakan" bagian yang saya sukai.
Michael Krelin - hacker
23
Anda mengabaikan hasOwnProperty()tes dan hal-hal yang sepertinya terus bekerja. Sampai mereka berhenti, karena objek Anda menjadi lebih kompleks dari waktu ke waktu. Kecuali kemudian rusak secara misterius di bagian kode yang tidak terkait karena terlalu banyak disalin. Dan Anda tidak memiliki konteks untuk debugging. JS menyebalkan seperti itu, jadi pengkodean yang hati-hati untuk mencegah masalah seperti itu terjadi adalah bijaksana.
Eli Bendersky
2
Saya pikir jawaban ini perlu diperbarui sesuai tautan developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… berikut const target = {a: 1, b: 2}; sumber const = {b: 4, c: 5}; const returnTarget = Object.assign (target, sumber); console.log (target); // hasil yang diharapkan: Objek {a: 1, b: 4, c: 5} console.log (returnsTarget); // hasil yang diharapkan: Objek {a: 1, b: 4, c: 5}
Elbassel
170

Mengambil petunjuk dari jawaban @ Bardzuśny di sini, ES6 telah memberikan solusi asli: Object.assign()fungsinya!

Penggunaannya sederhana:

Object.assign(secondObject, firstObject);

Itu dia!

Dukungan saat ini jelas buruk; hanya Firefox (34+) yang mendukungnya, sementara Chrome (45+) dan Opera (32+) membutuhkan 'flag eksperimental' yang harus ditetapkan.

Dukungan semakin membaik, dengan Chrome, Firefox, Opera, Safari, dan Edge versi terbaru mendukungnya (IE khususnya tidak memiliki dukungan.) Transpizer juga tersedia, seperti Babel dan Traceur. Lihat di sini untuk detail lebih lanjut.

Reaper DIMM
sumber
4
+1, fitur ES6 keren lainnya. Tentu saja browser / bahkan dukungan Node.JS masih kurang untuk saat ini, tetapi seperti yang Anda sebutkan, ada transponder yang tersedia. Dan jika Anda tidak menyukainya - shims: github.com/paulmillr/es6-shim (atau mandiri, Object.assign()-hanya shim: github.com/ljharb/object.assign ).
bardzusny
1
@Xoyce Jika Anda memeriksa halaman MDN tertaut, itu dengan jelas menyatakan "Jika nilai sumber adalah referensi ke objek, itu hanya menyalin nilai referensi itu." Jadi itu memang mempertahankan referensi, dan tidak menyalin objek. Peringatan Anda terhadap perilaku yang tidak terduga masih tepat, dan itu bermuara pada harapan yang tepat.
The DIMM Reaper
@mostafiz saya memutar kembali hasil edit Anda, karena pertanyaan dan jawaban lain pada halaman ini menggunakan nama "firstObject" dan "secondObject", jadi saya menggunakan nama yang sama di sini untuk kejelasan dan konsistensi.
The DIMM Reaper
Jika ini konsisten dengan pertanyaan maka tidak apa-apa.
Mostafiz Rahman
1
@ pdem Yap - lihat jawaban kingPuppy .
The DIMM Reaper
101

Per ES6 - Sebarkan sintaks :

Anda cukup menggunakan:

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

Ini menghindari masalah melewatkan benda-benda ini dengan referensi.

Selain itu merawat benda-benda yang memiliki sarang yang dalam.

kingPuppy
sumber
2
Wow, ini benar-benar hebat :) Terima kasih atas jawabannya. Jelas, saya tidak membutuhkannya lagi (karena beberapa waktu yang lalu), tetapi mungkin membantu orang lain
Igor Popov
1
+1 untuk penggunaan ES6 yang lebih keren! Dokumen MDN yang dirujuk di atas tidak menyebutkan penggunaan operator spread pada objek, jadi saya membuat biola untuk melihatnya dalam aksi: es6fiddle.net/im3ifsg0
The DIMM Reaper
1
@ situs - komentar yang baik untuk referensi. Sebuah benda (per pertanyaan asli) dengan nama properti sederhana adalah iterable.
kingPuppy
1
Berfungsi di Chrome, ini ES6, Anda akan membutuhkan Babel atau transpiler ES6 saat ini. Di masa depan semua browser diharapkan untuk mendukung sintaks ini.
kingPuppy
89

Ulangi properti dari objek pertama dan tetapkan ke objek kedua, seperti ini:

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

The for- inloop tidak cukup; kamu membutuhkan hasOwnProperty. Lihat http://bonsaiden.github.com/JavaScript-Garden/#object.forinloop untuk penjelasan terperinci tentang alasannya.

Ben Lee
sumber
@ Bob, saya tidak berpikir OP menggunakan referencedalam arti teknis. Saya pikir dia hanya berarti bahasa alami "merujuk ke".
Ben Lee
1
@RobW: OP benar-benar mengatakan "salin."
TJ Crowder
49

Bermain necromancer di sini, karena ES5 membawa kita Object.keys(), dengan potensi untuk menyelamatkan kita dari semua .hasOwnProperty()cek ini .

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

Atau, membungkusnya dalam suatu fungsi ("salinan" terbatas dari 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()adalah metode yang relatif baru, terutama: tidak tersedia di IE <9. Hal yang sama juga berlaku untuk .forEach()metode array, yang saya gunakan di tempat biasafor loop .

Untungnya ada es5-shim tersedia untuk browser kuno ini, yang akan mengisi banyak fitur ES5 (termasuk keduanya).

(Saya mendukung polyfill dan tidak menggunakan fitur bahasa baru yang keren.)

bardzusny
sumber
Tiba-tiba, 2 suara turun entah dari mana. Mengupayakan kecil kemungkinan orang-orang itu akan membaca komentar ini - apa alasan sebenarnya bagi mereka? Adakah yang akan Anda sarankan untuk berubah / tingkatkan dalam jawaban saya?
bardzusny
1
Ini pasti layak untuk naik ke atas, serta initializer penyebaran objek lebih jauh ke bawah (ES6) - ini terlihat lebih bersih dengan fungsi panah!
mjohnsonengr
12

Necro'ing sehingga orang-orang dapat menemukan metode penyalinan yang dalam dengan hasOwnProperty dan pemeriksaan objek aktual:

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
sumber
Perhatikan bahwa ini tidak menyalin-dalam array atau fungsi objek (tetapi tidak menyalin semua jenis objek lainnya).
Matt Browne
1
Ya, jika Anda ingin menyalin array yang dalam, Anda cukup memodifikasi jenis cek untuk menyertakan'[object Array]'
Nijikokun
12

Satu dapat menggunakan Object.assign untuk menggabungkan objek. Ini akan menggabungkan dan menimpa properti umum dari kanan ke kiri yaitu, properti yang sama di sebelah kiri akan ditimpa oleh kanan.

Dan penting untuk memasok objek kosong terlebih dahulu untuk menghindari mutasi objek sumber. Objek sumber harus dibiarkan bersih karena Object.assign()dengan sendirinya mengembalikan objek baru.

Semoga ini membantu!

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

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

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

console.log(finalObject)

Pranesh Ravi
sumber
tetapi bagaimana jika Anda ingin itu bermutasi objek pertama? Anda memiliki objek A dan objek B, dan Anda ingin mengubah objek A sehingga semua properti sama dengan apa yang ada di objek B? Apakah Anda akan melakukan Object.assign (A, B)?
TKoL
Sayangnya tidak didukung pada IE, Android WebView, Android Opera sesuai dengan halaman Jaringan Pengembang Mozilla.
Yetti99
6

Peningkatan ide kingPuppy dan ide OP (salinan dangkal) - Saya hanya menambahkan 3 titik ke OP "contoh" :)

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

Kamil Kiełczewski
sumber
4

Ini harus bekerja, diuji di sini .

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

Catatan : ini tidak akan menyalin metode firstObject
Catatan 2 : untuk digunakan di browser yang lebih lama, Anda akan memerlukan json parser
Catatan 3 : menetapkan dengan referensi adalah opsi yang layak, terutama jika firstObjectberisi metode. Menyesuaikan contoh jsfiddle yang diberikan sesuai

KooiInc
sumber
3

Sayangnya, Anda tidak dapat menempatkan referensi ke variabel di objek seperti itu. Namun, Anda bisa membuat fungsi yang menyalin nilai objek ke objek lain.

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 );
Akan
sumber
Ini juga akan menyalin properti asli. Dan bagaimana dengan properti yang merupakan Object itu sendiri?
KooiInc
1

Jika Anda ingin mengambil hanya properti yang ada di objek kedua, Anda bisa menggunakan Object.keysuntuk mengambil properti dari objek pertama, Anda bisa melakukan dua metode:

A.) map untuk menetapkan properti objek pertama ke objek kedua menggunakan efek samping:

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

B.) atau reduceuntuk membuat objek baru dan menetapkannya ke objek kedua. Ketahuilah bahwa metode ini menggantikan properti lain yang mungkin dimiliki objek kedua sebelum yang tidak cocok dengan objek pertama:

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
sumber
1

Gunakan notasi sebaran properti. Itu ditambahkan di ES2018 (spread untuk array / iterables sebelumnya, ES2015), {... firstObject} menyebar semua properti enumerable sebagai properti diskrit.

let secondObject = {
      ...firstObject,
      key3 : 'value3',
      key4 : 'value4'
    }
Anthony Awuley
sumber
dapatkah Anda memberikan beberapa konteks pada jawaban Anda dan mengapa itu memecahkan pertanyaan yang ada
Tamir Klein
0

Saya lebih suka menggunakan firstObject sebagai prototipe dari secondObject, dan menambahkan deskriptor properti:

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

Ini tentu saja tidak satu-liner, tetapi memberi Anda lebih banyak kontrol. Jika Anda tertarik dengan deskriptor properti, saya sarankan untuk membaca artikel ini: http://patrickdelancy.com/2012/09/property-descriptors-in-javascript/#comment-2062 dan halaman MDN https: //developer.mozilla. org / id-AS / docs / Web / JavaScript / Referensi / Global_Objects / Obyek / buat

Anda juga bisa hanya memberikan nilai dan menghilangkan deskriptor dan membuatnya sedikit lebih pendek:

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

Kompatibilitas: ECMAScript 5, jadi IE9 +

Ahmet Cetin
sumber
0
var firstObject = {
     key1: "value1",
     key2: "value2"
};

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

Menggunakan metode follwing akan menyalin properti

secondObject.copy(firstObject)

Saya sangat baru dalam javascript, tetapi ternyata ini berfungsi. Agak terlalu lama kurasa, tapi itu berhasil.

Sindhu Tirth
sumber