Come si copia una mappa in una mappa duplicata? [duplicare]


95

Come faccio a clonare / copiare una mappa in JavaScript?

So come clonare un array ma come clonare / copiare una mappa?

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(); 

3
ES6 ti permettelet copy = {...myMap};
Reactgular

Risposte:


15

Un modo semplice (per eseguire una copia superficiale) è copiare ogni proprietà della mappa di origine nella mappa di destinazione:

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

NOTA: newMap [i] potrebbe benissimo essere un riferimento allo stesso oggetto di myMap [i]


6
questa è solo una copia superficiale ... e se myMap [i] fosse una mappa stessa?
Stefano

1
Stefano, puoi farlo se vuoi (controlla se è un oggetto con typeof, quindi esegui una copia delle sue proprietà ... possibilmente ricorrendo alla stessa funzione), ma tieni presente che ora devi preoccuparti del possibilità che siano un elemento antenato nel loro che ti metterebbe in un ciclo infinito. Se vuoi davvero una copia completa, potresti voler esaminare le librerie per farlo.
rapina il

4
Lo so, ma penso che avresti dovuto scrivere questo nella tua risposta in primo luogo ;-)
Stefano

6
Questa non è una mappa ma un oggetto. Piccola e discreta differenza. cfr. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
helt

1
Non copierà ogni proprietà a cui non avrai accesso a setter e getter poiché è solo un oggetto
Amante Ninja

351

Con l'introduzione di Maps in JavaScript è abbastanza semplice considerando che il costruttore accetta un iterabile:

var newMap = new Map(existingMap)

Documentazione qui: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map


4
Un piccolo avvertimento a quanto sopra: la clonazione di una mappa come questa richiamerà Map.prototype.entriese Map.prototype.set. Ciò significa: se scrivi una classe che estende Map e sovrascrive uno di questi due metodi, la semplice scrittura new ExtendedMap( extendedMapObj )non funzionerà se i metodi estesi si basano su proprietà non disponibili per super.

clone profondo o solo clone superficiale? Diciamo che ho oggetti nidificati come valori
Madeo

ma fa una copia profonda o superficiale ??
Yonatan Nir,

5
Questo farà una copia superficiale, non profonda: jsfiddle.net/jormwe69
Jaap

1
@PeterCoester Possiamo dire che l'asintotico di var newMap = new Map(existingMap)è O(n)dov'è nil numero delle coppie chiave / valore della mappa? Immagino che l'operazione di clonazione non sia costante O(1)se, come dici tu, Map.prototype.entries viene chiamata sotto il cofano ...
tonix

10

Molto semplice clonare una mappa poiché quello di cui parli è solo un oggetto. C'è un Mapin ES6 che dovresti cercare, ma per copiare un oggetto, basta usareObject.assign()

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

Puoi anche usare cloneDeep()da Lodash

let copy = cloneDeep(map);

Object.assignAvviso per Deep Clone: ​​"Se il valore di origine è un riferimento a un oggetto, copia solo il valore di riferimento."
Tom Hale

6

JQuery ha un metodo per estendere un oggetto (unendo due oggetti), ma questo metodo può essere utilizzato anche per clonare un oggetto fornendo un oggetto vuoto.

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

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

Ulteriori informazioni possono essere trovate nella documentazione di jQuery .


3

Non c'è niente di integrato.

Utilizzare un copiatore di proprietà ricorsivo ben testato o, se le prestazioni non sono un problema, serializzare in JSON e analizzare di nuovo un nuovo oggetto.


2

Non esiste un clone / copia integrato. Puoi scrivere il tuo metodo su una copia superficiale o profonda:

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

Tutti gli oggetti in Javascript sono dinamici e possono essere assegnate nuove proprietà. Una "mappa" come la chiami è in realtà solo un oggetto vuoto. Un Array è anche un oggetto, con metodi come slicee proprietà simili length.


Non ho capito qual è la differenza tra le 2 funzioni che hai scritto!
Hasan A Yousef,

@HasanAYousef La differenza non è implementata; In una copia completa, è necessario ricorrere (chiamare deepCopy per ogni figlio), ma poiché i bambini possono contenere un riferimento al genitore (ad esempio window.window2 = finestra), non è possibile copiare completamente quei riferimenti senza entrare in un ciclo infinito.
Nicole

2

Se è necessario creare una copia completa di una mappa, è possibile utilizzare quanto segue:

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

Dove source l'oggetto Map originale.

Tieni presente che potrebbe non essere adatto a tutti i casi d'uso in cui i valori della mappa non sono serializzabili, per maggiori dettagli vedi: https://stackoverflow.com/a/122704/10583071


Ho eseguito un test su jsperf e ho scoperto che un approccio iterativo è 10 volte più veloce: jsperf.com/deep-copy-map
Zack Burt

3
@ZackBurt Purtroppo, la tua alternativa più veloce proposta non crea davvero un deep copyobiettivo Map, è solo un shallow copy. Forse è per questo che è così veloce?
Alfonso M. García Astorga

@ AlfonsoM.GarcíaAstorga Grazie per aver chiarito (votato di conseguenza). Lei ha ragione nel senso che è non è una copia profonda. Ma è una copia più veloce con <10kb di dati. Letture supplementari consigliate: v8.dev/blog/cost-of-javascript-2019#json
Zack Burt,

1

Ho notato che Map dovrebbe richiedere un trattamento speciale, quindi con tutti i suggerimenti in questo thread, il codice sarà:

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.