Bagaimana Cara Menyalin Peta ke Peta Duplikat? [duplikat]

95

Bagaimana cara mengkloning / menyalin peta di JavaScript?

Saya tahu cara mengkloning array tetapi bagaimana cara mengkloning / menyalin peta?

var myArray = new Array(1, 2, 3);
var copy    = myArray.slice();
// now I can change myArray[0] = 5; & it wont affect copy array

// Can I just do the same for map?
var myMap = new ?? // in javascript is it called a map?
var myMap = {"1": 1, "2", 2};
var copy  = myMap.slice(); 
sazr
sumber
3
ES6 memungkinkan Andalet copy = {...myMap};
Reactgular

Jawaban:

15

Cara sederhana (untuk melakukan salinan dangkal) adalah dengan menyalin setiap properti peta sumber ke peta target:

var newMap = {};
for (var i in myMap)
   newMap[i] = myMap[i];

CATATAN: newMap [i] bisa menjadi referensi ke objek yang sama dengan myMap [i]

rampok
sumber
6
ini hanya salinan dangkal ... bagaimana jika myMap [i] adalah peta itu sendiri?
Stefano
1
Stefano, Anda dapat melakukannya jika Anda mau (periksa apakah objek dengan typeof, kemudian lakukan salinan propertinya ... mungkin dengan menggunakan fungsi yang sama), tetapi perlu diingat bahwa sekarang Anda harus memperhatikan tentang kemungkinan mereka menjadi elemen leluhur yang akan menempatkan Anda dalam lingkaran tak terbatas. Jika Anda benar-benar menginginkan salinan yang dalam, Anda mungkin ingin melihat ke perpustakaan untuk melakukan itu.
merampok
4
Saya tahu, tetapi saya pikir Anda seharusnya menulis ini dalam jawaban Anda sejak awal ;-)
Stefano
6
Ini bukan Peta tapi Objek. Perbedaan kecil dan halus. cf. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
Helt
1
Ini tidak akan menyalin setiap properti yang Anda tidak memiliki akses ke setter dan getter karena itu hanya sebuah objek
Amante Ninja
351

Dengan pengenalan Maps di JavaScript, itu cukup sederhana mengingat konstruktor menerima iterable:

var newMap = new Map(existingMap)

Dokumentasi di sini: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map

tswaters
sumber
4
Peringatan kecil di atas: Mengkloning peta seperti ini, akan memanggil Map.prototype.entriesdan Map.prototype.set. Artinya: Jika Anda menulis kelas yang memperluas Map dan menimpa salah satu dari dua metode ini, maka hanya menulis new ExtendedMap( extendedMapObj )tidak akan berfungsi jika metode yang diperluas bergantung pada properti yang tidak tersedia untuk super.
apakah itu klon dalam atau hanya klon dangkal? Katakanlah saya memiliki objek bersarang sebagai nilai
Madeo
tetapi apakah itu melakukan salinan dalam atau dangkal ??
Yonatan Nir
5
Ini akan melakukan salinan dangkal, tidak dalam: jsfiddle.net/jormwe69
Jaap
1
@PeterCoester Bisakah kita mengatakan bahwa asimtotik var newMap = new Map(existingMap)adalah di O(n)mana njumlah pasangan kunci / nilai peta? Saya kira operasi kloning tidak konstan O(1)jika, seperti yang Anda katakan, Map.prototype.entries dipanggil di bawah tenda ...
tonix
10

Sangat mudah untuk mengkloning peta karena yang Anda bicarakan hanyalah sebuah objek. Ada Mapdi ES6 yang harus Anda cari, tetapi untuk menyalin objek, gunakan sajaObject.assign()

let map = {"a": 1, "b": 2}
let copy = Object.assign({}, map);

Anda juga dapat menggunakan cloneDeep()dari Lodash

let copy = cloneDeep(map);
Joshua Michael Wagoner
sumber
Object.assignPeringatan untuk Deep Clone: ​​"Jika nilai sumber adalah referensi ke objek, itu hanya menyalin nilai referensi."
Tom Hale
6

JQuery memiliki metode untuk memperluas suatu objek (menggabungkan dua objek), tetapi metode ini juga dapat digunakan untuk mengkloning suatu objek dengan menyediakan objek kosong.

// Shallow copy
var newObject = jQuery.extend({}, oldObject);

// Deep copy
var newObject = jQuery.extend(true, {}, oldObject);

Informasi lebih lanjut dapat ditemukan di dokumentasi jQuery .

Pastor Bones
sumber
3

Tidak ada yang terintegrasi.

Gunakan mesin fotokopi properti rekursif yang telah teruji dengan baik atau jika performa tidak menjadi masalah, buat serial ke JSON dan parsing lagi ke objek baru.

alex
sumber
2

Tidak ada klon / salin bawaan. Anda dapat menulis metode Anda sendiri ke salinan dangkal atau dalam:

function shallowCopy(obj) {
    var result = {};
    for (var i in obj) {
        result[i] = obj[i];
    }
    return result;
}

function deepCopy(obj) {
    var result = {};
    for (var i in obj) {
        // recursion here, though you'll need some non-trivial logic
        // to avoid getting into an endless loop.
    }
    return result;
}

Semua objek di Javascript bersifat dinamis, dan dapat diberi properti baru. Sebuah "peta" yang Anda rujuk sebenarnya hanyalah sebuah benda kosong. Array juga merupakan objek, dengan metode seperti slicedan properti seperti length.

Nicole
sumber
Tidak mengerti apa perbedaan antara 2 fungsi yang Anda tulis!
Hasan A Yousef
@HasanAYousef Perbedaannya tidak diterapkan; Dalam salinan dalam, Anda harus mengulang (panggil deepCopy untuk setiap anak), tetapi karena anak-anak mungkin berisi referensi ke induknya (misalnya window.window2 = window), Anda tidak dapat menyalin dalam-dalam referensi tersebut tanpa masuk ke loop tanpa akhir.
Nicole
2

Jika Anda perlu membuat salinan dalam dari Peta, Anda dapat menggunakan yang berikut ini:

new Map(JSON.parse(JSON.stringify(Array.from(source))));

Dimana sourceobjek Map asli.

Perhatikan ini mungkin tidak cocok untuk semua kasus penggunaan di mana nilai Peta tidak dapat diserialkan, untuk lebih jelasnya lihat: https://stackoverflow.com/a/122704/10583071

robdc
sumber
Saya menjalankan pengujian di jsperf dan menemukan bahwa pendekatan berulang 10x lebih cepat: jsperf.com/deep-copy-map
Zack Burt
2
@ZackBurt Sayangnya, alternatif yang Anda usulkan lebih cepat tidak benar-benar membuat deep copytarget Mapitu hanya a shallow copy. Mungkin ini sebabnya begitu cepat?
Alfonso M. García Astorga
@ AlfonsoM.GarcíaAstorga Terima kasih telah mengklarifikasi (upvoting sesuai). Anda benar karena ini bukan salinan yang dalam. Tapi ini lebih cepat menyalin dengan <10kb data. Bacaan tambahan yang disarankan: v8.dev/blog/cost-of-javascript-2019#json
Zack Burt
1

Saya perhatikan bahwa Map harus memerlukan perlakuan khusus, jadi dengan semua saran di utas ini, kode akan menjadi:

function deepClone( obj ) {
    if( !obj || true == obj ) //this also handles boolean as true and false
        return obj;
    var objType = typeof( obj );
    if( "number" == objType || "string" == objType ) // add your immutables here
        return obj;
    var result = Array.isArray( obj ) ? [] : !obj.constructor ? {} : new obj.constructor();
    if( obj instanceof Map )
        for( var key of obj.keys() )
            result.set( key, deepClone( obj.get( key ) ) );
    for( var key in obj )
        if( obj.hasOwnProperty( key ) )
            result[key] = deepClone( obj[ key ] );
    return result;
}
Dmitriy Pichugin
sumber