Bagaimana cara menggabungkan dua objek javascript bersama di ES6 +?

141

Saya muak dengan selalu harus menulis kode seperti ini:

function shallowExtend(obj1,obj2){
  var key;
  for ( key in obj2 ) {
    if ( obj2.hasOwnProperty(key) === false )  continue;
    obj1[key] = obj2[key]
  }
}

Atau jika saya tidak ingin menulis kode sendiri, terapkan perpustakaan yang sudah melakukannya. Tentunya ES6 + akan datang untuk menyelamatkan ini akan memberi kita sesuatu seperti Object.prototype.extend(obj2...)atauObject.extend(obj1,obj2...)

Jadi apakah ES6 + menyediakan fungsionalitas seperti itu? Jika belum ada di sana, maka apakah fungsi tersebut direncanakan? Jika tidak direncanakan, lalu mengapa tidak?

balupton
sumber
3
Jadi mengapa Anda belum menambahkannya ke perpustakaan Anda ?
RobG
12
@RobG pertanyaan ini adalah tentang harapan bahwa ES6 akan menghapus kita dari keharusan membutuhkan omong kosong seperti boilerplate di tempat pertama. Untuk apa nilainya: github.com/balupton/bal-util/blob/…
balupton
Saya tidak berpikir ada cara umum untuk menyalin pasangan nama / nilai dari satu objek ke objek lain. Apakah Anda hanya berurusan dengan properti sendiri atau properti yang ada di [[Prototype]]rantai? Apakah Anda membuat salinan "dalam" atau "dangkal"? Bagaimana dengan properti non-enumerable dan non-dapat ditulis? Saya pikir saya lebih suka memiliki fungsi perpustakaan kecil yang melakukan apa yang saya butuhkan, dan sebagian besar itu bisa dihindari.
RobG

Jawaban:

206

Anda akan dapat melakukan penggabungan / perluasan / penetapan dangkal di ES6 dengan menggunakan Object.assign:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

Sintaksis:

Object.assign ( target , sumber );

di mana ... sumber mewakili objek sumber.

Contoh:

var obj1 = {name: 'Daisy', age: 30};
var obj2 = {name: 'Casey'};

Object.assign(obj1, obj2);

console.log(obj1.name === 'Casey' && obj1.age === 30);
// true
Mendongkrak
sumber
64
Catatan kecil: Object.assign mengubah target. Jika bukan itu yang Anda inginkan, Anda dapat menyebutnya dengan objek kosong:let merged = Object.assign({}, source1, source2);
david
20
Harap perhatikan ini adalah perluasan dangkal ... objek bersarang TIDAK digabungkan
monzonj
@monzonj, apakah tidak ada opsi untuk memperluas objek bersarang, tanpa menggunakan lodash atau mout?
Joao Falcao
1
Ada cara yang baik untuk menggabungkan benda-benda yang bersarang secara mendalam tanpa perpustakaan hanya menggunakan Object.assign: lihat jawaban saya di sini
Ruslan
Cara lama untuk memperluas objek bersarang menggunakanJSON.parse(JSON.stringify(src))
Andre Figueiredo
162

Anda dapat menggunakan sintaks penyebaran objek untuk ini:

const merged = {...obj1, ...obj2}

Untuk array operator spread sudah menjadi bagian dari ES6 (ES2015), tetapi untuk objek ditambahkan ke spec bahasa di ES9 (ES2018). Usulannya telah diaktifkan secara default di alat-alat seperti Babel jauh sebelum itu.

Thijs Koerselman
sumber
3
Tidak secara resmi sekarang disebut ES2015: P Sejak kapan perusakan bukan bagian dari ES6? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Menjalankan babel-node: const ob1 = {foo: 123}; const ob2 = {bar: 234}; const merged = {...ob1, ...ob2}; console.log(merged) Output:{ foo: 123, bar: 234 }
Thijs Koerselman
9
Itu bukan merusak, itu menyebar - dan tidak, untuk objek itu bukan bagian dari ES6. Anda harus menonaktifkan konsep ES7 eksperimental di babel Anda.
Bergi
2
Ah maafkan aku. Kamu benar. Ini adalah fitur babel stage 2 saat ini. github.com/sebmarkbage/ecmascript-rest-spread Saya tidak pernah menyadari itu karena saya sudah menggunakannya sejak awal dengan babel dan diaktifkan secara default. Tetapi karena Anda harus melakukan transpile, dan penyebaran objek adalah hal yang cukup mudah, saya akan merekomendasikannya. Aku menyukainya.
Thijs Koerselman
Mereka diaktifkan secara default, benarkah? Itu terdengar seperti bug.
Bergi
2
"Proposal yang tingkat 2 atau di atasnya diaktifkan secara default". babeljs.io/docs/usage/experimental
Thijs Koerselman
14

Saya tahu ini sedikit masalah lama tapi solusi termudah di ES2015 / ES6 sebenarnya cukup sederhana, menggunakan Object.assign (),

Semoga ini bisa membantu, ini juga menggabungkan DEEP :

/**
 * Simple is object check.
 * @param item
 * @returns {boolean}
 */
export function isObject(item) {
  return (item && typeof item === 'object' && !Array.isArray(item) && item !== null);
}

/**
 * Deep merge two objects.
 * @param target
 * @param source
 */
export function mergeDeep(target, source) {
  if (isObject(target) && isObject(source)) {
    for (const key in source) {
      if (isObject(source[key])) {
        if (!target[key]) Object.assign(target, { [key]: {} });
        mergeDeep(target[key], source[key]);
      } else {
        Object.assign(target, { [key]: source[key] });
      }
    }
  }
  return target;
}

Contoh penggunaan:

mergeDeep(this, { a: { b: { c: 123 } } });
// or
const merged = mergeDeep({a: 1}, { b : { c: { d: { e: 12345}}}});  
console.dir(merged); // { a: 1, b: { c: { d: [Object] } } }
Salakar
sumber
7

Penambahan Object.mixinsaat ini sedang dibahas untuk menangani perilaku yang Anda minta. https://mail.mozilla.org/pipermail/es-discuss/2012-December/027037.html

Meskipun belum ada dalam draft ES6, sepertinya ada banyak dukungan untuk itu, jadi saya pikir ini akan segera muncul di draft.

Nathan Wall
sumber
13
.mixintelah dijatuhkan oleh TC39.
Knu
5
Peringatan - jawaban ini tidak lagi benar, lihat jawaban oleh Jack untuk pendekatan yang benar dan bekerja.
Benjamin Gruenbaum
Object.mixin telah digantikan oleh Object.assign
gotofritz
7

ES6

Object.assign(o1,o2) ; 
Object.assign({},o1,o2) ; //safe inheritance
var copy=Object.assign({},o1); // clone o1
//------Transform array of objects to one object---
var subjects_assess=[{maths:92},{phy:75},{sport:99}];
Object.assign(...subjects_assess); // {maths:92,phy:75,sport:99}

ES7 atau Babel

{...o1,...o2} // inheritance
 var copy= {...o1};
Abdennour TOUMI
sumber
1
@FilipBartuzi itu bukan ES6 yang Anda tautkan. Tetapi pada dasarnya melakukan hal yang sama dengan _.extend () di lodash / garis bawah.
Nostalg.io
5

Mungkin Object.definePropertiesmetode ES5 akan melakukan pekerjaan itu?

misalnya

var a = {name:'fred'};
var b = {age: {value: 37, writeable: true}};

Object.defineProperties(a, b);

alert(a.age); // 37

Dokumentasi MDN: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperties

RobG
sumber
Namun berhati-hatilah. Pada setidaknya satu browser ini memiliki implikasi kinerja.
Reuben Morais
1
Saya pikir yang paling menarik adalah definePropertiesmendefinisikan properti sendiri. Itu tidak menimpa properti pada [[prototype]]rantai, itu membayangi mereka.
RobG
2
Saran yang baik, meskipun tidak benar-benar meluas karena lebih untuk mendefinisikan bagaimana sifat harus berperilaku ... Melakukan Object.defineProperties langsung (obj1, obj2) akan menyebabkan hasil yang tidak terduga.
balupton
harus menggunakan Object.getOwnPropertyDescriptorjuga untuk mengatur properti ketika itu adalah nilai yang kompleks, atau Anda akan menyalin dengan referensi.
dmp