Klonen / Kopieren einer Map-Instanz [Duplikat]

93

Wie klone / kopiere ich eine Karte in JavaScript?

Ich weiß, wie man ein Array klont, aber wie klone / kopiere ich eine Karte?

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
quelle
2
ES6 lässt Sielet copy = {...myMap};
Reactgular

Antworten:

15

Eine einfache Möglichkeit (eine flache Kopie zu erstellen) besteht darin, jede Eigenschaft der Quellkarte auf die Zielkarte zu kopieren:

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

HINWEIS: newMap [i] kann sehr gut eine Referenz auf dasselbe Objekt wie myMap [i] sein.

rauben
quelle
6
Dies ist nur eine flache Kopie ... Was ist, wenn myMap [i] selbst eine Karte ist?
Stefano
1
Stefano, Sie können dies tun, wenn Sie möchten (prüfen Sie, ob es sich um ein Objekt mit typeof handelt, und führen Sie dann eine Kopie seiner Eigenschaften durch ... möglicherweise durch Rekursion derselben Funktion), aber denken Sie daran, dass Sie sich jetzt Gedanken über das machen müssen Möglichkeit, dass sie ein Ahnenelement in ihrem sind, das Sie in eine Endlosschleife bringen würde. Wenn Sie wirklich eine tiefe Kopie wünschen, sollten Sie sich dazu die Bibliotheken ansehen.
Rob
4
Ich weiß, aber ich denke, du hättest das zuerst in deine Antwort schreiben sollen ;-)
Stefano
5
Dies ist keine Karte, sondern ein Objekt. Kleiner und kleiner Unterschied. vgl. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
helt
1
Es wird nicht jede Eigenschaft kopiert, auf die Sie keinen Zugriff auf Setter und Getter haben, da es nur ein Objekt ist
Amante Ninja
346

Mit der Einführung von Maps in JavaScript ist es recht einfach, wenn man bedenkt, dass der Konstruktor eine Iterable akzeptiert:

var newMap = new Map(existingMap)

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

tswaters
quelle
4
Eine kleine Einschränkung: Wenn Sie eine Karte wie diese klonen, wird Map.prototype.entriesund aufgerufen Map.prototype.set. Das bedeutet: Wenn Sie eine Klasse schreiben, die Map erweitert und eine dieser beiden Methoden überschreibt, new ExtendedMap( extendedMapObj )funktioniert das einfache Schreiben nicht, wenn die erweiterten Methoden auf Eigenschaften beruhen, die dem Super nicht zur Verfügung stehen.
Klont es tief oder nur flach? Angenommen, ich habe ein verschachteltes Objekt als Werte
Madeo
aber macht es eine tiefe oder eine flache Kopie?
Yonatan Nir
5
Dies wird eine flache Kopie machen, nicht tief: jsfiddle.net/jormwe69
Jaap
1
@PeterCoester Können wir sagen, dass die Asymptotik von var newMap = new Map(existingMap)ist, O(n)wo ndie Anzahl der Schlüssel / Wert-Paare der Karte ist? Ich denke, dass der O(1)Map.prototype.entries
Klonvorgang
11

Es ist sehr einfach, eine Karte zu klonen, da es sich bei dem, worüber Sie sprechen, nur um ein Objekt handelt. Es gibt eine Mapin ES6, die Sie nachschlagen sollten, aber um ein Objekt zu kopieren, verwenden Sie einfachObject.assign()

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

Sie können auch cloneDeep()von Lodash verwenden

let copy = cloneDeep(map);
Joshua Michael Waggoner
quelle
Object.assignWarnung für Deep Clone: ​​"Wenn der Quellwert eine Referenz auf ein Objekt ist, wird nur der Referenzwert kopiert."
Tom Hale
6

JQuery verfügt über eine Methode zum Erweitern eines Objekts (Zusammenführen von zwei Objekten). Diese Methode kann jedoch auch zum Klonen eines Objekts verwendet werden, indem ein leeres Objekt bereitgestellt wird.

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

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

Weitere Informationen finden Sie in der jQuery-Dokumentation .

Pastor Bones
quelle
3

Es ist nichts eingebaut.

Verwenden Sie entweder einen gut getesteten rekursiven Eigenschaftskopierer oder, wenn die Leistung kein Problem darstellt, serialisieren Sie in JSON und analysieren Sie erneut ein neues Objekt.

Alex
quelle
2

Es ist kein Klon / keine Kopie integriert. Sie können Ihre eigene Methode entweder in eine flache oder eine tiefe Kopie schreiben:

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

Alle Objekte in Javascript sind dynamisch und können neuen Eigenschaften zugewiesen werden. Eine "Karte", wie Sie sich darauf beziehen, ist eigentlich nur ein leeres Objekt. Ein Array ist auch ein Objekt mit Methoden wie sliceund Eigenschaften wie length.

Nicole
quelle
Ich habe nicht verstanden, was der Unterschied zwischen den beiden Funktionen ist, die Sie geschrieben haben!
Hasan A Yousef
@HasanAYousef Der Unterschied ist nicht implementiert; In einer tiefen Kopie müssen Sie eine Rekursion durchführen (für jedes Kind deepCopy aufrufen). Da Kinder jedoch möglicherweise einen Verweis auf das übergeordnete Element enthalten (z. B. window.window2 = window), können Sie diese Verweise nicht tief kopieren, ohne in eine Endlosschleife zu geraten.
Nicole
2

Wenn Sie eine tiefe Kopie einer Karte erstellen müssen, können Sie Folgendes verwenden:

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

Wo sourceist das ursprüngliche Kartenobjekt?

Beachten Sie, dass dies möglicherweise nicht für alle Anwendungsfälle geeignet ist, in denen die Kartenwerte nicht serialisierbar sind. Weitere Informationen finden Sie unter: https://stackoverflow.com/a/122704/10583071

robdc
quelle
Ich habe einen Test auf jsperf durchgeführt und festgestellt, dass ein iterativer Ansatz 10x schneller ist: jsperf.com/deep-copy-map
Zack Burt
2
@ZackBurt Leider schafft Ihre schnellere vorgeschlagene Alternative nicht wirklich ein deep copyZiel, Mapsondern nur ein shallow copy. Vielleicht ist es deshalb so schnell?
Alfonso M. García Astorga
@ AlfonsoM.GarcíaAstorga Vielen Dank für die Klarstellung (entsprechend positiv bewertet). Sie haben insofern Recht, als es sich nicht um eine tiefe Kopie handelt. Es ist jedoch eine schnellere Kopie mit <10 KB Daten. Empfohlene ergänzende Lektüre: v8.dev/blog/cost-of-javascript-2019#json
Zack Burt
1

Mir ist aufgefallen, dass Map eine besondere Behandlung erfordern sollte. Bei allen Vorschlägen in diesem Thread lautet der Code daher:

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
quelle