Tiefes Kopieren von Objekten in Angular

70

AngularJS muss angular.copy()Objekte und Arrays tief kopieren.

Hat Angular auch so etwas?

Ankit Singh
quelle
5
Mögliches Duplikat von Wie kann ich Angular.copy in Angular 2 verwenden?
Günter Zöchbauer
Duplicatevielleicht, aber ich wollte eine non-polyfillLösung. genau wieangular.copy()
Ankit Singh
Das ist alles was wir haben.
Günter Zöchbauer
Also nein angular.copy()hmm. Soll ich die Frage löschen?
Ankit Singh
Ich denke schon. Scheint nicht viel Wert zu bieten, um es zu behalten, da es auch eine ganz ähnliche Frage gibt.
Günter Zöchbauer

Antworten:

85

Sie können auch verwenden:

JSON.parse(JSON.stringify(Object))

Wenn es sich in Ihrem Bereich befindet, befindet es sich in jeder Angular-Komponente, Direktive usw. und auch in jeder Knotenumgebung.

Sofern Sie keine Zirkelreferenz haben, sollte diese funktionieren und Ihre Variablenreferenz effektiv vom ursprünglichen Objekt trennen.

Gabriel Balsa Cantú
quelle
1
Dies scheint eine sehr einfache und effektive tiefe Kopie zu sein! Warum ist das nicht höher? Stimmt etwas mit dieser Antwort nicht?
TSG
Für eine Deep-Copy-Lösung, bei der alle Verweise entfernt werden, ist dies die beste Methode, die in Browser / CommonJS usw. verfügbar ist. Ich verwende sie in der Produktion, wenn ein Objekt-Snapshot benötigt wird. Ich schätze, ich bin angekommen, um etwas spät zu antworten, wie 1 Jahr zu spät. @ TSG
Gabriel Balsa Cantú
2
Wenn Sie ein Objektliteral mit Funktionen verwenden (nicht nur Werte), werden diese weggelassen, aber Sie können sie leicht kombinieren. Object.assing({}, oldObject, JSON.parse(JSON.stringify(oldObject)))Dadurch werden Ihre Funktionseigenschaften aus Ihrem Objektliteral neu gefüllt und mit JSON wird eine tiefe Kopie ohne erstellt jede Beziehung zum Original.
Gabriel Balsa Cantú
Beste Antwort meiner Meinung nach
Johannes Wanzek
3
Beachten Sie jedoch, dass dies bei einigen Daten nicht funktioniert.
František Žiačik
22

Diese Frage ist kein Duplikat von Wie kann ich angle.copy in Angular 2 verwenden, da das OP nach tiefen Kopierobjekten fragt ? In der verknüpften Antwort wird Object.assign () empfohlen, das keine tiefe Kopie erstellt.

Die Verwendung von Angular2 hindert Sie nicht daran, andere Bibliotheken wie jQuery zum tiefen Kopieren von Objekten mit ihrer Funktion $ .clone () oder lodash mit _.cloneDeep () zu verwenden .

Die gängigsten Bibliotheken verfügen über Typisierungs- CLI-Tools, sodass Sie auch beim Transpilieren von TypeScript nahtlos alles verwenden können, was Sie möchten.

Siehe auch: Was ist der effizienteste Weg, um ein Objekt in JavaScript tief zu klonen?

Martin
quelle
Object.assign () kopiert nicht tief, wenn sich verschachtelte Objekte im Zielobjekt befinden. Als naive Lösung können Sie das Zielobjekt durchgehen und Object.assign () für jede Eigenschaft des Objekts ausführen! Es hat bei mir funktioniert, als ich nicht von einer Drittanbieter-Bibliothek abhängig sein wollte
Dany Wehbe
21

Eine andere Möglichkeit besteht darin, eine eigene Funktion zu implementieren:

/**
 * Returns a deep copy of the object
 */
public static deepCopy(oldObj: any) {
    var newObj = oldObj;
    if (oldObj && typeof oldObj === "object") {
        if (oldObj instanceof Date) {
           return new Date(oldObj.getTime());
        }
        newObj = Object.prototype.toString.call(oldObj) === "[object Array]" ? [] : {};
        for (var i in oldObj) {
            newObj[i] = this.deepCopy(oldObj[i]);
        }
    }
    return newObj;
}
Andrea Ialenti
quelle
1
Ich bin nicht in der Lage, Daten mit dieser Methode tief zu kopieren
A_J
Ich habe einen Klon von Datum hinzugefügt, basierend auf dem Klonen eines
Datumsobjekts
11

Sie können deep copyein Objekt in Angular mit der cloneDeep-Methode von lodash erstellen:

Installieren Sie lodash mit yarn add lodashoder npm install lodash.

Importieren cloneDeepund verwenden Sie es in Ihrer Komponente :

import * as cloneDeep from 'lodash/cloneDeep';
...
clonedObject = cloneDeep(originalObject);

Es sind nur 18 KB zu Ihrem Build hinzugefügt, was sich für die Vorteile lohnt.

Ich habe hier auch einen Artikel geschrieben , wenn Sie mehr darüber erfahren möchten, warum Sie lodashs cloneDeep verwenden.

BogdanC
quelle
Das Kopieren nach Wert hat bei mir mit Lodash nicht funktioniert. Weißt du vielleicht warum? Ich erhalte immer noch referenzierte Werte, daher ändern sich beide gleichzeitig, wenn ich einen ändere.
Vladimir Despotovic
5
Create helper class with name deepCopy.ts

/*
* DeepCopy class helps to copy an Original Array or an Object without impacting on original data
*/

export class DeepCopy {

  static copy(data: any) {
    let node;
    if (Array.isArray(data)) {
      node = data.length > 0 ? data.slice(0) : [];
      node.forEach((e, i) => {
        if (
          (typeof e === 'object' && e !== {}) ||
          (Array.isArray(e) && e.length > 0)
        ) {
          node[i] = DeepCopy.copy(e);
        }
      });
    } else if (data && typeof data === 'object') {
      node = data instanceof Date ? data : Object.assign({}, data);
      Object.keys(node).forEach((key) => {
        if (
          (typeof node[key] === 'object' && node[key] !== {}) ||
          (Array.isArray(node[key]) && node[key].length > 0)
        ) {
          node[key] = DeepCopy.copy(node[key]);
        }
      });
    } else {
      node = data;
    }
    return node;
  }
}

Importieren Sie die deepCopy-Datei, wo immer Sie sie benötigen, und verwenden Sie den folgenden Code: DeepCopy.copy (arg); Hier würde arg entweder Objekt oder Array, das Sie wollen

Krishnamraju K.
quelle
Dies ist eigentlich die beste Antwort. Es kopiert Daten effektiv tief, ohne externe Bibliotheken zu importieren. Ich möchte nicht eine ganze Bibliothek einbinden, um nur eine Funktion zu verwenden (auch wenn es nur 18 KB sind).
Frozenfrank
1

Wenn die Quelle ein Array von Objekten ist , verwenden Sie map:

let cloned = source.map(x => Object.assign({}, x));

ODER

let cloned = source.map((x) => {
                return { ...x };
             });
Lahar Shah
quelle
1

Einige Modifikationen für KrishnamrajuKs Antwort

export class DeepCopy {
  static copy(data: any, objMap?: WeakMap<any, any>) {
    if (!objMap) {
      // Map for handle recursive objects
      objMap = new WeakMap();
    }

    // recursion wrapper
    const deeper = value => {
      if (value && typeof value === 'object') {
        return DeepCopy.copy(value, objMap);
      }
      return value;
    };

    // Array value
    if (Array.isArray(data)) return data.map(deeper);

    // Object value
    if (data && typeof data === 'object') {
      // Same object seen earlier
      if (objMap.has(data)) return objMap.get(data);
      // Date object
      if (data instanceof Date) {
        const result = new Date(data.valueOf());
        objMap.set(data, result);
        return result;
      }
      // Use original prototype
      const node = Object.create(Object.getPrototypeOf(data));
      // Save object to map before recursion
      objMap.set(data, node);
      for (const [key, value] of Object.entries(data)) {
        node[key] = deeper(value);
      }
      return node;
    }
    // Scalar value
    return data;
  }
}

vp_arth
quelle
0

Ich stehe vor dem Problem des tiefen Kopierens. angular.copy ({}, factory) und angular.extend ({}, factory) eignen sich gut für Array- oder Hashing-Objekte. Beim Kopieren eines Objekts in einen Calass kann es jedoch manchmal zu Problemen mit verbundenen Abhängigkeiten kommen. Ich habe dieses Problem so gelöst:

 copyFactory = (() ->
    resource = ->
      resource.__super__.constructor.apply this, arguments
      return
    this.extendTo resource
    resource
  ).call(factory)
Vitya Ivliiev
quelle
-1

Ich habe eine sehr einfache Funktion in Typoskript erstellt, die alle möglichen Eingaben akzeptiert und die tief geklonte Kopie dieses Objekts liefert.

Hoffe es wird jemandem helfen.

  public deepCopy(obj) {

    var clonedObject: any;

    if (obj instanceof Array) {
        var itemArray = Object.assign([], obj);
        clonedObject = itemArray;

        for (var j = 0; j < clonedObject.length; j++) {
            clonedObject[j] = this.deepCopy(clonedObject[j]);
        }

        return clonedObject;
    }
    else if (typeof obj === 'number' || typeof obj == 'string') {
        return obj
    }
    else {


        var item = Object.assign({}, obj);
        clonedObject = item;

        let allKeys = Object.keys(clonedObject);

        for (var i = 0; i < allKeys.length; i++) {
            if (clonedObject[allKeys[i]] instanceof Array) {
                //If the calue is Array
                clonedObject[allKeys[i]] = this.deepCopy(clonedObject[allKeys[i]]);
            }
            else if (clonedObject[allKeys[i]] instanceof Date) {
                clonedObject[allKeys[i]] = new Date(clonedObject[allKeys[i]].valueOf());
            }
            else if (clonedObject[allKeys[i]] instanceof Object){
                //if the value is JOBJECT.
                clonedObject[allKeys[i]] = this.deepCopy(clonedObject[allKeys[i]]);
            }
        }
        return clonedObject;
    }


}
Anil kumar
quelle