Bagaimana menggabungkan properti dari beberapa objek JavaScript

105

Saya mencari cara terbaik untuk "menambahkan" beberapa objek JavaScript (array asosiatif).

Misalnya, diberikan:

a = { "one" : 1, "two" : 2 };
b = { "three" : 3 };
c = { "four" : 4, "five" : 5 };

apa cara terbaik untuk menghitung:

{ "one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }
Vlad
sumber
3
Catatan semantik: terlepas dari sintaks [], mereka sama sekali bukan array. Pesanan tidak benar-benar dijamin.
Álvaro González
1
Urutan iterasi tidak dijamin sesuai standar ecma. Tetapi ini adalah cara penerapannya di sebagian besar browser. (Dari John Resig) Perilaku ini secara eksplisit tidak ditentukan oleh spesifikasi ECMAScript. Dalam ECMA-262, bagian 12.6.4: Mekanisme penghitungan properti ... bergantung pada implementasi. Namun, spesifikasi sangat berbeda dengan implementasi. Semua implementasi modern ECMAScript melakukan iterasi melalui properti objek dalam urutan yang mereka tetapkan. Karenanya, tim Chrome menganggap ini sebagai bug dan akan memperbaikinya.
Juan Mendes

Jawaban:

159

ECMAscript 6 diperkenalkan Object.assign()untuk mencapai ini secara native dalam Javascript.

Metode Object.assign () digunakan untuk menyalin nilai dari semua properti enumerable sendiri dari satu atau lebih objek sumber ke objek target. Ini akan mengembalikan objek target.

Dokumentasi MDN di Object.assign ()

var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };

var obj = Object.assign({}, o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }

Object.assigndidukung di banyak browser modern, tetapi belum semuanya. Gunakan transpiler seperti Babel dan Traceur untuk menghasilkan JavaScript ES5 yang kompatibel dengan versi sebelumnya.

filoxo.dll
sumber
4
Ini adalah salah satu yang terbaik yang bisa saya katakan. Karena E6 sekarang banyak digunakan, Object.assign adalah jawaban terbaik.
Vimalraj Selvam
6
Jika Anda tidak tahu berapa banyak objek yang perlu digabungkan, karena objek tersebut berada dalam array Anda dapat menggabungkannya sebagai berikut:Object.assign.apply({}, [{a: 1}, {b: 2}, ....])
Jeanluca Scaljeri
1
Alternatif untuk menggunakan Object.assign.applyuntuk menggabungkan larik objek, adalah dengan menggunakan operator penyebaran:Object.assign( ...objects )
Spen
@Spen yang sudah disertakan sebagai jawaban untuk pertanyaan ini. Saya tidak melihat manfaat untuk menduplikasinya di sini.
filoxo
setelah 4 jam, jawaban ini menyelesaikan masalah saya di Angular 7. Terima kasih atas kesederhanaan dan ketepatan jawaban.
Gel
35

Anda bisa menggunakan jquery $.extendseperti ini:

let a = { "one" : 1, "two" : 2 },
    b = { "three" : 3 },
    c = { "four" : 4, "five" : 5 };

let d = $.extend({}, a, b, c)

console.log(d)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

adiga
sumber
+1 Bahkan jika Anda tidak menggunakan metode jQuery, Anda dapat menggunakan kode mereka untuk membantu membangun implementasi Anda sendiri (mungkin, lebih spesifik).
tvanfosson
25
@Randal: Ada banyak alasan bagus untuk tidak menggunakan jQuery.
Tim Down
3
Edit:d = $.extend({},a,b,c);
Bob Stein
34

Ini harus melakukannya:

function collect() {
  var ret = {};
  var len = arguments.length;
  for (var i = 0; i < len; i++) {
    for (p in arguments[i]) {
      if (arguments[i].hasOwnProperty(p)) {
        ret[p] = arguments[i][p];
      }
    }
  }
  return ret;
}

let a = { "one" : 1, "two" : 2 };
let b = { "three" : 3 };
let c = { "four" : 4, "five" : 5 };

let d = collect(a, b, c);
console.log(d);

Keluaran:

{
  "one": 1,
  "two": 2,
  "three": 3,
  "four": 4,
  "five": 5
}
cletus
sumber
Tidak lengthmencari ukuran larik di setiap pemanggilan? Saya sangat terbiasa menulis for (var i = 0, len = array.length; i < len; ++i)sehingga saya tidak dapat mengingat sepenuhnya mengapa saya mulai melakukannya.
tvanfosson
1
Ya benar. Ini adalah kinerja yang lebih baik untuk menyimpan panjang cache sekali. Namun, karena ukuran argumen "larik" tidak akan pernah terlalu besar, itu tidak akan menjadi masalah dalam kasus ini.
jhurshman
1
Tidak, kecuali sedikit di IE6. Mengakses properti panjang biayanya sama dengan mengakses variabel len.
Alsciende
1
@Juan Saya yakin Anda salah, dan saya melakukan beberapa tes untuk mengambil keputusan. Caching panjangnya adalah mitos mudah tentang pengoptimalan yang sudah usang selama bertahun-tahun, dan itu membuat kode (sedikit) kurang dapat dibaca. Sebenarnya, panjang cache terkadang memperlambat browser (Safari).
Alsciende
2
Bukankah lebih baik menulis 'for (var p in ...' daripada 'for (p in ...'?
Hugo
24

ECMAScript 6 telah menyebarkan sintaks . Dan sekarang Anda bisa melakukan ini:

const obj1 = { 1: 11, 2: 22 };
const obj2 = { 3: 33, 4: 44 };
const obj3 = { ...obj1, ...obj2 };

console.log(obj3); // {1: 11, 2: 22, 3: 33, 4: 44}

valex
sumber
12

Menggarisbawahi memiliki beberapa metode untuk melakukan ini;

1. _.extend (tujuan, * sumber)

Salin semua properti di objek sumber ke objek tujuan , dan kembalikan objek tujuan .

_.extend(a, _.extend(b, c));
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

Atau

_.extend(a, b);
=> {"one" : 1, "two" : 2, "three" : 3}
_.extend(a, c);
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

2. _.defaults (objek, * defaults)

Isi properti yang tidak ditentukan dalam objek dengan nilai dari objek default , dan kembalikan objek tersebut .

_.defaults(a, _.defaults(b, c));
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

Atau

_.defaults(a, b);
=> {"one" : 1, "two" : 2, "three" : 3}
_.defaults(a, c);
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }
gihanchanuka
sumber
4

Mengapa fungsi harus dibatasi ke 3 argumen? Periksa juga hasOwnProperty.

function Collect() {
    var o={};
    for(var i=0;i<arguments.length;i++) {
      var arg=arguments[i];
      if(typeof arg != "object") continue;
      for(var p in arg) {
        if(arg.hasOwnProperty(p)) o[p] = arg[p];
      }
    }
    return o;
}
Alsciende
sumber
4

Kloning dangkal (tidak termasuk prototipe) atau penggabungan objek sekarang dapat dilakukan menggunakan sintaks yang lebih pendek dari Object.assign () .

Sintaks penyebaran untuk literal objek diperkenalkan di ECMAScript 2018 ):

const a = { "one": 1, "two": 2 };
const b = { "three": 3 };
const c = { "four": 4, "five": 5 };

const result = {...a, ...b, ...c};
// Object { "one": 1, "two": 2 , "three": 3, "four": 4, "five": 5 }

Operator Spread (...) didukung di banyak browser modern tetapi tidak semuanya.

Jadi, disarankan untuk menggunakan transpiler seperti Babel untuk mengubah kode ECMAScript 2015+ menjadi versi JavaScript yang kompatibel dengan versi sebelumnya di browser atau lingkungan lama dan lama.

Ini adalah kode setara yang akan dihasilkan Babel untuk Anda:

"use strict";

var _extends = Object.assign || function(target) {
  for (var i = 1; i < arguments.length; i++) {
    var source = arguments[i];
    for (var key in source) {
      if (Object.prototype.hasOwnProperty.call(source, key)) {
        target[key] = source[key];
      }
    }
  }
  return target;
};

var a = { "one": 1, "two": 2 };
var b = { "three": 3 };
var c = { "four": 4, "five": 5 };

var result = _extends({}, a, b, c);
// Object { "one": 1, "two": 2 , "three": 3, "four": 4, "five": 5 }
Thiago Santos
sumber
Ini adalah jawaban yang jauh lebih kuat daripada jawaban yang diterima. Terima kasih!
Kaleb Anderson
3
function Collect(a, b, c) {
    for (property in b)
        a[property] = b[property];

    for (property in c)
        a[property] = c[property];

    return a;
}

Perhatian: Properti yang ada di objek sebelumnya akan ditimpa.

Björn
sumber
2
Ini memiliki efek samping yang a === dpada akhirnya. Itu mungkin baik-baik saja dan mungkin juga tidak.
tvanfosson
2

Sangat mudah menggunakan operator penyebaran ES7 untuk suatu objek, di konsol browser Anda

({ name: "Alex", ...(true  ? { age: 19 } : { })}) // {name: "Alex", age: 19}
({ name: "Alex", ...(false ? { age: 19 } : { })}) // {name: "Alex",        }
Purkhalo Alex
sumber
1
Bagus. Pertanyaan ini sudah berusia lebih dari 10 tahun, senang karena pengoperasian yang sederhana sekarang mudah. Tidak semudah itu sebelumnya jika Anda melihat jawaban orang lain.
Vlad
itu sebabnya saya meninggalkan jawaban saya sendiri :)
Purkhalo Alex
2

Untuk menggabungkan sejumlah dinamis objek, kita dapat menggunakan Object.assigndengan spread sintaks .

const mergeObjs = (...objs) => Object.assign({}, ...objs);

Fungsi di atas menerima sejumlah objek, menggabungkan semua propertinya menjadi objek baru dengan properti dari objek selanjutnya menimpa objek dari objek sebelumnya.

Demo:

Untuk menggabungkan larik objek, metode serupa dapat diterapkan.

const mergeArrayOfObjs = arr => Object.assign({}, ...arr);

Demo:

hev1
sumber
1

Mungkin, cara tercepat, efisien, dan lebih umum adalah ini (Anda dapat menggabungkan sejumlah objek dan bahkan menyalin ke yang pertama -> assign):

function object_merge(){
    for (var i=1; i<arguments.length; i++)
       for (var a in arguments[i])
         arguments[0][a] = arguments[i][a];
   return arguments[0];
}

Ini juga memungkinkan Anda untuk memodifikasi objek pertama saat melewati referensi. Jika Anda tidak menginginkan ini tetapi ingin memiliki objek yang benar-benar baru yang berisi semua properti, maka Anda bisa meneruskan {} sebagai argumen pertama.

var object1={a:1,b:2};
var object2={c:3,d:4};
var object3={d:5,e:6};
var combined_object=object_merge(object1,object2,object3); 

gabungan_objek dan objek1 keduanya berisi properti objek1, objek2, objek3.

var object1={a:1,b:2};
var object2={c:3,d:4};
var object3={d:5,e:6};
var combined_object=object_merge({},object1,object2,object3); 

Dalam kasus ini, gabungan_object berisi properti object1, object2, object3 tetapi object1 tidak dimodifikasi.

Periksa di sini: https://jsfiddle.net/ppwovxey/1/

Catatan: objek JavaScript diteruskan dengan referensi.

Selay
sumber
1

ES6 ++

Pertanyaannya adalah menambahkan berbagai berbeda benda menjadi satu.

let obj = {};
const obj1 = { foo: 'bar' };
const obj2 = { bar: 'foo' };
Object.assign(obj, obj1, obj2);
//output => {foo: 'bar', bar: 'foo'};

katakanlah Anda memiliki satu objek dengan beberapa kunci yang merupakan objek:

let obj = {
  foo: { bar: 'foo' },
  bar: { foo: 'bar' }
}

ini adalah solusi yang saya temukan (masih harus foreach: /)

let objAll = {};

Object.values(obj).forEach(o => {
  objAll = {...objAll, ...o};
});

Dengan melakukan ini kita dapat secara dinamis menambahkan SEMUA kunci objek menjadi satu.

// Output => { bar: 'foo', foo: 'bar' }
Joseph Briggs
sumber
0

Paling sederhana: operator penyebaran

var obj1 = {a: 1}
var obj2 = {b: 2}
var concat = { ...obj1, ...obj2 } // { a: 1, b: 2 }
Rodolfo Paranhos
sumber
-2
function collect(a, b, c){
    var d = {};

    for(p in a){
        d[p] = a[p];
    }
    for(p in b){
        d[p] = b[p];
    }
    for(p in c){
        d[p] = c[p];
    }

    return d;
}
Álvaro González
sumber