Menggabungkan objek (array asosiatif)

147

Apa cara terbaik / standar untuk menggabungkan dua array asosiatif dalam JavaScript? Apakah semua orang hanya melakukannya dengan memutar forlingkaran mereka sendiri ?

Wilhelm
sumber
10
tidak ada array asosiatif dalam javascript btw, hanya objek.
gblazex
Crossref pertanyaan yang sama di Perl: stackoverflow.com/questions/350018/…
dreftymac
Array asosiatif dalam javascript: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Chris Martin

Jawaban:

204

dengan jquery Anda bisa menelepon $.extend

var obj1 = {a: 1, b: 2};
var obj2 = {a: 4, c: 110};

var obj3 = $.extend(obj1, obj2); 

obj1 == obj3 == {a: 4, b: 2, c: 110} // Pseudo JS

(assoc. array adalah objek di js)

lihat di sini: http://api.jquery.com/jQuery.extend/


sunting: Seperti yang disarankan rymo, lebih baik melakukannya dengan cara ini:

obj3 = $.extend({}, obj1, obj2); 
obj3 == {a: 4, b: 2, c: 110}

Seperti di sini obj1 (dan obj2) tetap tidak berubah.


sunting2: Pada tahun 2018 cara untuk melakukannya adalah melalui Object.assign:

var obj3 = Object.assign({}, obj1, obj2); 
obj3 === {a: 4, b: 2, c: 110} // Pseudo JS

Jika bekerja dengan ES6 ini dapat dicapai dengan Penyebar Operator :

const obj3 = { ...obj1, ...obj2 };
kulpae
sumber
54
atau untuk menghindari mucking obj1, gunakan objek kosong sebagai target:$.extend({}, obj1, obj2)
rymo
Ya, ketika berhadapan dengan penutupan dan objek yang dilewatkan dengan referensi, ikuti saran rymo untuk menghindari memengaruhi objek asli untuk operasi selanjutnya.
Nathan Smith
2
Untuk peramban modern, periksa solusinya dengan @manfred using Object.assign(), yang tidak bergantung pada JQuery jika Anda belum menggunakan perpustakaan.
Phil
Ini berfungsi, tetapi mengubah parameter pertama dan itu adalah sesuatu yang perlu Anda waspadai. Lihat developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
kulpae
62

Sekarang di 2016 saya akan mengatakan cara terbaik / standar adalah Object.assign ()
Javascript Murni. Tidak diperlukan jQuery.

obj1 = {a: 1, b: 2};
obj2 = {a: 4, c: 110};
obj3 = Object.assign({},obj1, obj2);  // Object {a: 4, b: 2, c: 110}

Informasi lebih lanjut, contoh dan polyfill di sini:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

Manfred
sumber
Apa jenis untuk obj3? bagaimana jika obj1 adalah tipe IABC, akankah obj3 menyimpan tipe itu setelahnya?
windmaomao
49

Inilah cara Prototype melakukannya:

Object.extend = function(destination, source) {
    for (var property in source) {
        if (source.hasOwnProperty(property)) {
            destination[property] = source[property];
        }
    }
    return destination;
};

disebut sebagai, misalnya:

var arr1 = { robert: "bobby", john: "jack" };
var arr2 = { elizabeth: "liz", jennifer: "jen" };

var shortnames = Object.extend(arr1,arr2);

EDIT : menambahkan hasOwnProperty () periksa sebagaimana ditunjukkan oleh bucabay dalam komentar

Jonathan Fingland
sumber
6
Anda akan memerlukan sumber tes.hasOwnProperty (properti) untuk memastikan Anda hanya menyalin properti langsung. Seperti ini, ini bisa menyalin semua properti termasuk yang berasal dari Object.prototype
bucabay
22

Sederhana saja ...

function mergeArray(array1,array2) {
  for(item in array1) {
    array2[item] = array1[item];
  }
  return array2;
}
Chris Scerbo
sumber
6
Anda harus memeriksa hasOwnProperty untuk menghindari menyalin properti apa pun diarrau1.prototype
LeeGee
@ LeeGee benar. Anda perlu hasOwnPropertycek itu. Mengacu pada objek sebagai array juga menyesatkan (mereka objek), nama-nama arg harus menyampaikan bahwa array2 dimutasi atau objek baru harus dikembalikan. Saya akan mengedit jawaban tetapi pada dasarnya itu akan menjadi jawaban yang persis diedit Jonathan Fingland yang telah diperbaiki.
Vaz
14

Garis bawah juga memiliki metode perluasan:

Salin semua properti di objek sumber ke objek tujuan. Ini tidak berurutan, jadi sumber terakhir akan menimpa properti dengan nama yang sama dalam argumen sebelumnya.

_.extend(destination, *sources) 

_.extend({name : 'moe'}, {age : 50});
=> {name : 'moe', age : 50}
Mike McKay
sumber
7

Di dojo , 2-objek / array "merge" adalah lang.mixin(destination, source)- Anda juga dapat mencampur beberapa sumber menjadi satu tujuan, dll - lihat referensi fungsi mixin untuk detailnya.

Alex Martelli
sumber
6

apakah Anda ingin menimpa properti jika namanya sama tetapi nilainya tidak?

Dan apakah Anda ingin secara permanen mengubah salah satu objek asli,

atau Anda ingin objek yang digabungkan kembali?

function mergedObject(obj1, obj2, force){
    for(var p in obj1) this[p]= obj1[p];
    for(var p in obj2){
        if(obj2.hasOwnProperty(p)){
            if(force || this[p]=== undefined) this[p]= obj2[p];
            else{
                n= 2;
                while(this[p+n]!== undefined)++n;
                this[p+n]= obj2[p];
            }
        }
    }
}
kennebec
sumber
6

Menggulung Fungsi Perpanjangan / Campuran Anda Sendiri

function extend(objects) {
    var args
        , first = Array.prototype.slice.call(arguments, 0, 1)[0]
        , second;

    if (arguments.length > 1) {
        second = Array.prototype.splice.call(arguments, 1, 1)[0];
        for (var key in second) {
            first[key] = second[key];
        }
        args = Array.prototype.slice.call(arguments, 0);
        return extend.apply(this, args);
    }

    return first;
}

...

var briansDirections = {
    step1: 'Remove pastry from wrapper.',
    step2: 'Place pastry toaster.',
    step3: 'Remove pastry from toaster and enjoy.',
};
extend(briansDirections, { step1: 'Toast Poptarts' }, { step2: 'Go ahead, toast \'em' }, { step3: 'Hey, are you sill reading this???' });

...

Ini hanya memperluas percikan objek, secara rekursif. Juga, perhatikan bahwa fungsi rekursif ini adalah TCO ( Tail-Call Dioptimalkan ) karena kembalinya adalah panggilan terakhir untuk dirinya sendiri.

Selain itu, Anda mungkin menginginkan properti yang ditargetkan . Dalam hal ini, Anda mungkin ingin untuk menyingkat objek berdasarkan id, quantityatau properti lain. Pendekatan ini dapat memiliki buku kecil yang ditulis tentang hal itu dan memerlukan penjajaran objek dan bisa menjadi sangat kompleks. Saya telah menulis perpustakaan kecil untuk ini yang tersedia berdasarkan permintaan.

Semoga ini membantu!

Cody
sumber
4
  1. Dalam Javascript tidak ada gagasan array asosiatif, ada objek
  2. Satu-satunya cara untuk menggabungkan dua objek adalah dengan loop untuk propertinya dan menyalin pointer ke nilainya yang bukan tipe primitif dan nilai untuk tipe primitif ke instance lain
Sergey Ilinsky
sumber
8
Objek dalam Javascript diimplementasikan sebagai array asosiatif, jadi tentu saja ada gagasan yang sama
Dexygen
2

Pada 2019 Anda memiliki 2 opsi yang baik:

Penugasan objek [ doc ]

const result = Object.assign({}, baseObject, updatingObject);

Penyebaran objek [ doc ]

const result = { ...baseObject, ...updatingObject};

Yang pertama cenderung lebih aman, lebih standar dan polivalen. Pro dan kontra yang bagus di sini

VincentPerrin.com
sumber
1

Yahoo UI (YUI) juga memiliki fungsi pembantu untuk ini:

http://developer.yahoo.com/yui/examples/yahoo/yahoo_merge.html

YAHOO.namespace('example');

YAHOO.example.set1 = { foo : "foo" };
YAHOO.example.set2 = { foo : "BAR", bar : "bar" };
YAHOO.example.set3 = { foo : "FOO", baz : "BAZ" };

var Ye = YAHOO.example;

var merged = YAHOO.lang.merge(Ye.set1, Ye.set2, Ye.set3);
Ben Walding
sumber
1

jquery memiliki boolean untuk salinan dalam. Anda dapat melakukan sesuatu seperti itu:

MergeRecursive = function(arr1, arr2){
    $.extend(true, arr1, arr2);
    return arr1;                
};

Anda juga dapat mengedit fungsi ini untuk mendukung n-array untuk digabung.

ArrayMergeRecursive = function(){
     if(arguments.length < 2){
          throw new Error("ArrayMergeRecursive: Please enter two or more objects to merge!");
     }

    var arr1=arguments[0];
    for(var i=0; i<=arguments.length; i++ ){
        $.extend(true, arr1, arguments[i]);                 
    }

    return arr1;                
};

Jadi sekarang bisa kamu lakukan

var arr1 = {'color': {'mycolor': 'red'}, 3: 5},
    arr2 = {4: 10, 'color': {'favorite': 'green', 0: 'blue'}},
    arr3 = ['Peter','Jhon','Demosthenes'],
    results = ArrayMergeRecursive(arr1, arr2, arr3); // (arr1, arr2 ... arrN)
console.log("Result is:", results);
demosthenes
sumber
0

Saya membutuhkan penggabungan objek dalam. Jadi semua jawaban lain tidak banyak membantu saya. _.extend dan jQuery.extend melakukannya dengan baik, kecuali Anda memiliki array rekursif seperti yang saya lakukan. Tapi itu tidak terlalu buruk, Anda dapat memprogramnya dalam lima menit:

var deep_merge = function (arr1, arr2) {
    jQuery.each(arr2, function (index, element) {
        if (typeof arr1[index] === "object" && typeof element === "object") {
            arr1[index] = deep_merge(arr1[index], element);
        } else if (typeof arr1[index] === "array" && typeof element === "array") {
            arr1[index] = arr1[index].concat(element);
        } else {
            arr1[index] = element;
        }
    });
    return arr1;
}
Rasmus
sumber
0

Untuk menggabungkan array di jQuery, bagaimana dengan $ .merge?

var merged = $.merge([{id:3, value:'foo3'}], [{id:1, value:'foo1'}, {id:2, value:'foo2'}]);
merged[0].id == 3;
merged[0].value == 'foo3';
merged[1].id == 1;
merged[1].value == 'foo1';
merged[2].id == 2;
merged[2].value == 'foo2';
Rogério R. Alcântara
sumber
0

Solusi rekursif (meluas juga array objek) + null diperiksa

var addProps = function (original, props) {
    if(!props) {
        return original;
    }
    if (Array.isArray(original)) {
        original.map(function (e) {
            return addProps(e, props)
        });
        return original;
    }
    if (!original) {
        original = {};
    }
    for (var property in props) {
        if (props.hasOwnProperty(property)) {
            original[property] = props[property];
        }
    }
    return original;
};

Tes

console.log(addProps([{a: 2}, {z: 'ciao'}], {timestamp: 13}));
console.log(addProps({single: true}, {timestamp: 13}));
console.log(addProps({}, {timestamp: 13}));
console.log(addProps(null, {timestamp: 13}));

[ { a: 2, timestamp: 13 }, { z: 'ciao', timestamp: 13 } ]
{ single: true, timestamp: 13 }
{ timestamp: 13 }
{ timestamp: 13 }
sscarduzio
sumber
Saya mencoba menggunakan ini dengan Node JS, tetapi Object.getOwnPropertyNames is not a functionakan merusak aplikasi.
Legoless
Saya menggunakan ini dengan beberapa mesin v8 oldish dalam ekstensi PostgreSQL plv8. Dan itu berfungsi di browser. Cukup cari cara di mesin JS Anda untuk melakukan hal yang sama dengan "hasOwnProperty". Kemudian Anda dapat menggunakan kembali logika ini.
sscarduzio
0

Inilah solusi terbaik.

obj1.unshift.apply( obj1, obj2 );

Juga, obj1bisa tumbuh di dalam lingkaran tanpa masalah. (katakanlah obj2dinamis)

bilen
sumber