it-swarm-eu.dev

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

Was ist der effizienteste Weg, um ein JavaScript-Objekt zu klonen? Ich habe gesehen, dass obj = eval(uneval(o)); verwendet wird, aber das ist kein Standard und wird nur von Firefox unterstützt .

Ich habe Dinge wie obj = JSON.parse(JSON.stringify(o)); gemacht, aber die Effizienz in Frage gestellt. 

Ich habe auch rekursive Kopierfunktionen mit verschiedenen Fehlern gesehen.
Ich bin überrascht, dass es keine kanonische Lösung gibt.

4863
jschrab

Anmerkung von 2019 bis Juni: Dies war ursprünglich eine Antwort auf eine andere Antwort, keine richtige Antwort auf diese Frage. Keine Ahnung, warum es als die richtige Antwort ausgewählt wurde. Da die Upvotes jedoch zugenommen haben und dies bei weitem die beste Antwort auf diese Frage ist, werden die Lösungen als Wiki-Antwort zusammengefasst.

Eingeborenes tiefes Klonen

Es heißt "strukturiertes Klonen", funktioniert experimentell in Node 11 und höher und landet hoffentlich in Browsern. Siehe diese Antwort für weitere Einzelheiten.

Schnelles Klonen bei Datenverlust - JSON.parse/stringify

Wenn Sie Dates, functions, undefined, Infinity, RegExps, Maps, Sets, Blobs, FileLists, ImageDatas, sparse Arrays, typisierte Arrays oder andere komplexe Typen in Ihrem Objekt nicht verwenden, können Sie ein Objekt auf einfache Weise tief klonen:

JSON.parse(JSON.stringify(object))

_const a = {
  string: 'string',
  number: 123,
  bool: false,
  nul: null,
  date: new Date(),  // stringified
  undef: undefined,  // lost
  inf: Infinity,  // forced to 'null'
  re: /.*/,  // lost
}
console.log(a);
console.log(typeof a.date);  // Date object
const clone = JSON.parse(JSON.stringify(a));
console.log(clone);
console.log(typeof clone.date);  // result of .toISOString()_

Siehe Corbans Antwort für Benchmarks.

Zuverlässiges Klonen mit einer Bibliothek

Da das Klonen von Objekten nicht trivial ist (komplexe Typen, Zirkelverweise, Funktionen usw.), bieten die meisten wichtigen Bibliotheken Funktionen zum Klonen von Objekten. Rad nicht neu erfinden - Wenn Sie bereits eine Bibliothek verwenden, prüfen Sie, ob sie eine Funktion zum Klonen von Objekten enthält. Zum Beispiel,

ES6

Beachten Sie der Vollständigkeit halber, dass ES6 zwei flache Kopiermechanismen bietet: Object.assign() und spread operator .

4379
John Resig

Diesen Benchmark überprüfen: http://jsben.ch/#/bWfk9

In meinen vorherigen Tests, bei denen Geschwindigkeit ein Hauptanliegen war, fand ich heraus 

JSON.parse(JSON.stringify(obj))

um die schnellste Möglichkeit zu sein, ein Objekt tief zu klonen (es schlägt aus jQuery.extend mit einem tiefen Flag, das auf 10-20% gesetzt ist).

jQuery.extend ist ziemlich schnell, wenn das tiefe Flag auf false (shallow clone) gesetzt ist. Dies ist eine gute Option, da sie einige zusätzliche Logik für die Typüberprüfung enthält und keine undefinierten Eigenschaften usw. kopiert. Dies wird Sie jedoch etwas verlangsamen.

Wenn Sie die Struktur der Objekte kennen, die Sie zu klonen versuchen oder tief verschachtelte Arrays vermeiden können, können Sie eine einfache for (var i in obj)-Schleife zum Klonen Ihres Objekts schreiben, während Sie hasOwnProperty prüfen. Dies ist viel schneller als jQuery.

Wenn Sie versuchen, eine bekannte Objektstruktur in einer Hot-Loop zu klonen, können Sie VIEL VIEL MEHR LEISTUNG erhalten, indem Sie einfach die Klonprozedur einbetten und das Objekt manuell erstellen.

JavaScript-Trace-Engines saugen die Optimierung von for..in-Schleifen und die Überprüfung von hasOwnProperty verlangsamt Sie ebenfalls. Manueller Klon, wenn Geschwindigkeit ein absolutes Muss ist.

var clonedObject = {
  knownProp: obj.knownProp,
  ..
}

Vorsicht bei der Verwendung der JSON.parse(JSON.stringify(obj))-Methode für Date-Objekte - JSON.stringify(new Date()) gibt eine Zeichenfolgendarstellung des Datums im ISO-Format zurück, die JSON.parse()nicht zurück in ein Date-Objekt konvertiert. Siehe diese Antwort für weitere Details .

Beachten Sie außerdem, dass zumindest in Chrome 65 das native Klonen nicht der richtige Weg ist. Laut dieser JSPerf ist das native Klonen mit dem Erstellen einer neuen Funktion fast 800x langsamer als mit JSON.stringify, was auf der ganzen Welt unglaublich schnell ist.

2066
Corban Brook

Angenommen, Sie haben nur Variablen und keine Funktionen in Ihrem Objekt, können Sie einfach Folgendes verwenden:

var newObject = JSON.parse(JSON.stringify(oldObject));
434
Sultan Shakir

Strukturiertes Klonen

Der HTML-Standard enthält einen internen strukturierten Klonierungs-/Serialisierungsalgorithmus , der tiefe Klone von Objekten erstellen kann. Es ist immer noch auf bestimmte integrierte Typen beschränkt, aber zusätzlich zu den wenigen von JSON unterstützten Typen unterstützt es auch Datumsangaben, RegExps, Maps, Sets, Blobs, FileLists, ImageDatas, spärliche Arrays, typisierte Arrays und möglicherweise mehr . Außerdem werden Referenzen innerhalb der geklonten Daten beibehalten, sodass zyklische und rekursive Strukturen unterstützt werden können, die zu Fehlern bei JSON führen würden.

Unterstützung in Node.js: Experimentell ????

Das v8-Modul in Node.js ist derzeit (ab Node 11) macht die API für die strukturierte Serialisierung direkt zugänglich , diese Funktionalität ist jedoch weiterhin als "experimentell" gekennzeichnet und kann in zukünftigen Versionen geändert oder entfernt werden. Wenn Sie eine kompatible Version verwenden, ist das Klonen eines Objekts so einfach wie folgt:

const v8 = require('v8');

const structuredClone = obj => {
  return v8.deserialize(v8.serialize(obj));
};

Direkter Support in Browsern: Eventuell vielleicht? ????

Browser bieten derzeit keine direkte Schnittstelle für den strukturierten Klonierungsalgorithmus, aber eine globale structuredClone()-Funktion wurde in whatwg/html # 793 in GitHub besprochen. Wie derzeit vorgeschlagen, wäre die Verwendung für die meisten Zwecke so einfach wie:

const clone = structuredClone(original);

Wenn dies nicht ausgeliefert wird, werden die strukturierten Klonimplementierungen von Browsern nur indirekt angezeigt.

Asynchrone Problemumgehung: Verwendbar. ????

Der geringere Aufwand zum Erstellen eines strukturierten Klons mit vorhandenen APIs besteht darin, die Daten über einen Port eines MessageChannels zu senden. Der andere Port gibt ein message -Ereignis mit einem strukturierten Klon des angehängten .data aus. Leider ist das Abhören dieser Ereignisse notwendigerweise asynchron und die synchronen Alternativen sind weniger praktisch.

class StructuredCloner {
  constructor() {
    this.pendingClones_ = new Map();
    this.nextKey_ = 0;

    const channel = new MessageChannel();
    this.inPort_ = channel.port1;
    this.outPort_ = channel.port2;

    this.outPort_.onmessage = ({data: {key, value}}) => {
      const resolve = this.pendingClones_.get(key);
      resolve(value);
      this.pendingClones_.delete(key);
    };
    this.outPort_.start();
  }

  cloneAsync(value) {
    return new Promise(resolve => {
      const key = this.nextKey_++;
      this.pendingClones_.set(key, resolve);
      this.inPort_.postMessage({key, value});
    });
  }
}

const structuredCloneAsync = window.structuredCloneAsync =
    StructuredCloner.prototype.cloneAsync.bind(new StructuredCloner);

Beispiel Verwendung:

const main = async () => {
  const original = { date: new Date(), number: Math.random() };
  original.self = original;

  const clone = await structuredCloneAsync(original);

  // They're different objects:
  console.assert(original !== clone);
  console.assert(original.date !== clone.date);

  // They're cyclical:
  console.assert(original.self === original);
  console.assert(clone.self === clone);

  // They contain equivalent values:
  console.assert(original.number === clone.number);
  console.assert(Number(original.date) === Number(clone.date));

  console.log("Assertions complete.");
};

main();

Synchronous Workarounds: Schrecklich! ????

Es gibt keine guten Optionen, um strukturierte Klone synchron zu erstellen. Hier sind ein paar unpraktische Hacks.

history.pushState() und history.replaceState() erstellen beide einen strukturierten Klon ihres ersten Arguments und weisen diesen Wert history.state zu. Sie können dies verwenden, um einen strukturierten Klon eines beliebigen Objekts wie folgt zu erstellen:

const structuredClone = obj => {
  const oldState = history.state;
  history.replaceState(obj, null);
  const clonedObj = history.state;
  history.replaceState(oldState, null);
  return clonedObj;
};

Beispiel Verwendung:

'use strict';

const main = () => {
  const original = { date: new Date(), number: Math.random() };
  original.self = original;

  const clone = structuredClone(original);
  
  // They're different objects:
  console.assert(original !== clone);
  console.assert(original.date !== clone.date);

  // They're cyclical:
  console.assert(original.self === original);
  console.assert(clone.self === clone);

  // They contain equivalent values:
  console.assert(original.number === clone.number);
  console.assert(Number(original.date) === Number(clone.date));
  
  console.log("Assertions complete.");
};

const structuredClone = obj => {
  const oldState = history.state;
  history.replaceState(obj, null);
  const clonedObj = history.state;
  history.replaceState(oldState, null);
  return clonedObj;
};

main();

Obwohl synchron, kann dies extrem langsam sein. Es verursacht den gesamten Aufwand für die Bearbeitung des Browserverlaufs. Ein wiederholtes Aufrufen dieser Methode kann dazu führen, dass Chrome vorübergehend nicht mehr reagiert.

Der Notification-Konstruktor erstellt einen strukturierten Klon der zugehörigen Daten. Es wird auch versucht, eine Browserbenachrichtigung für den Benutzer anzuzeigen, dies schlägt jedoch automatisch fehl, wenn Sie keine Benachrichtigungsberechtigung angefordert haben. Falls Sie die Berechtigung für andere Zwecke haben, schließen wir die von uns erstellte Benachrichtigung umgehend.

const structuredClone = obj => {
  const n = new Notification('', {data: obj, silent: true});
  n.onshow = n.close.bind(n);
  return n.data;
};

Beispiel Verwendung:

'use strict';

const main = () => {
  const original = { date: new Date(), number: Math.random() };
  original.self = original;

  const clone = structuredClone(original);
  
  // They're different objects:
  console.assert(original !== clone);
  console.assert(original.date !== clone.date);

  // They're cyclical:
  console.assert(original.self === original);
  console.assert(clone.self === clone);

  // They contain equivalent values:
  console.assert(original.number === clone.number);
  console.assert(Number(original.date) === Number(clone.date));
  
  console.log("Assertions complete.");
};

const structuredClone = obj => {
  const n = new Notification('', {data: obj, silent: true});
  n.close();
  return n.data;
};

main();

308
Jeremy Banks

Wenn es keinen eingebauten gibt, können Sie Folgendes versuchen:

function clone(obj) {
    if (obj === null || typeof (obj) !== 'object' || 'isActiveClone' in obj)
        return obj;

    if (obj instanceof Date)
        var temp = new obj.constructor(); //or new Date(obj);
    else
        var temp = obj.constructor();

    for (var key in obj) {
        if (Object.prototype.hasOwnProperty.call(obj, key)) {
            obj['isActiveClone'] = null;
            temp[key] = clone(obj[key]);
            delete obj['isActiveClone'];
        }
    }
    return temp;
}
295
ConroyP

Die effiziente Methode zum Klonen (nicht Klonen) eines Objekts in einer Codezeile

Eine Object.assign -Methode ist Teil des Standards ECMAScript 2015 (ES6) und erfüllt genau das, was Sie benötigen.

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

Die Object.assign () -Methode wird verwendet, um die Werte aller aufzählbaren eigenen Eigenschaften von einem oder mehreren Quellobjekten in ein Zielobjekt zu kopieren.

Weiterlesen...

Die polyfill zur Unterstützung älterer Browser:

if (!Object.assign) {
  Object.defineProperty(Object, 'assign', {
    enumerable: false,
    configurable: true,
    writable: true,
    value: function(target) {
      'use strict';
      if (target === undefined || target === null) {
        throw new TypeError('Cannot convert first argument to object');
      }

      var to = Object(target);
      for (var i = 1; i < arguments.length; i++) {
        var nextSource = arguments[i];
        if (nextSource === undefined || nextSource === null) {
          continue;
        }
        nextSource = Object(nextSource);

        var keysArray = Object.keys(nextSource);
        for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
          var nextKey = keysArray[nextIndex];
          var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
          if (desc !== undefined && desc.enumerable) {
            to[nextKey] = nextSource[nextKey];
          }
        }
      }
      return to;
    }
  });
}
149
Eugene Tiurin

Code:

// extends 'from' object with members from 'to'. If 'to' is null, a deep clone of 'from' is returned
function extend(from, to)
{
    if (from == null || typeof from != "object") return from;
    if (from.constructor != Object && from.constructor != Array) return from;
    if (from.constructor == Date || from.constructor == RegExp || from.constructor == Function ||
        from.constructor == String || from.constructor == Number || from.constructor == Boolean)
        return new from.constructor(from);

    to = to || new from.constructor();

    for (var name in from)
    {
        to[name] = typeof to[name] == "undefined" ? extend(from[name], null) : to[name];
    }

    return to;
}

Prüfung:

var obj =
{
    date: new Date(),
    func: function(q) { return 1 + q; },
    num: 123,
    text: "asdasd",
    array: [1, "asd"],
    regex: new RegExp(/aaa/i),
    subobj:
    {
        num: 234,
        text: "asdsaD"
    }
}

var clone = extend(obj);
94
Kamarey

Das verwende ich:

function cloneObject(obj) {
    var clone = {};
    for(var i in obj) {
        if(typeof(obj[i])=="object" && obj[i] != null)
            clone[i] = cloneObject(obj[i]);
        else
            clone[i] = obj[i];
    }
    return clone;
}
86
Alan

Tiefe Kopie nach Aufführung: Bestnoten bis Schlechteste

  • Neuzuordnung "=" (nur String-Arrays, Zahlen-Arrays)
  • Slice (nur String-Arrays, nur Zahlen-Arrays)
  • Verkettung (nur String-Arrays, nur Number-Arrays)
  • Benutzerdefinierte Funktion: für die Schleife oder rekursive Kopie
  • jQuery's $ .extend
  • JSON.parse (nur String-Arrays, Zahlen-Arrays, Objekt-Arrays)
  • Underscore.js _s _.clone (nur String-Arrays, Zahlen-Arrays)
  • Lo-Dash's _.cloneDeep

Deep kopiert ein Array von Strings oder Zahlen (eine Ebene - keine Referenzzeiger):

Wenn ein Array Zahlen und Strings enthält - Funktionen wie .slice (), .concat (), .splice (), der Zuweisungsoperator "=" und die Klonfunktion von Underscore.js; erstellt eine tiefe Kopie der Elemente des Arrays.

Wo die Neuzuweisung die schnellste Leistung aufweist:

var arr1 = ['a', 'b', 'c'];
var arr2 = arr1;
arr1 = ['a', 'b', 'c'];

Und .slice () hat eine bessere Leistung als .concat (), http://jsperf.com/duplicate-array-slice-vs-concat/3

var arr1 = ['a', 'b', 'c'];  // Becomes arr1 = ['a', 'b', 'c']
var arr2a = arr1.slice(0);   // Becomes arr2a = ['a', 'b', 'c'] - deep copy
var arr2b = arr1.concat();   // Becomes arr2b = ['a', 'b', 'c'] - deep copy

Tiefes Kopieren eines Arrays von Objekten (zwei oder mehr Ebenen - Referenzzeiger):

var arr1 = [{object:'a'}, {object:'b'}];

Schreiben Sie eine benutzerdefinierte Funktion (hat eine schnellere Leistung als $ .extend () oder JSON.parse):

function copy(o) {
   var out, v, key;
   out = Array.isArray(o) ? [] : {};
   for (key in o) {
       v = o[key];
       out[key] = (typeof v === "object" && v !== null) ? copy(v) : v;
   }
   return out;
}

copy(arr1);

Verwenden Sie Dienstprogramme von Drittanbietern:

$.extend(true, [], arr1); // Jquery Extend
JSON.parse(arr1);
_.cloneDeep(arr1); // Lo-dash

Wo jQuery's $ .extend eine bessere Leistung bringt:

73
tfmontague
var clone = function() {
    var newObj = (this instanceof Array) ? [] : {};
    for (var i in this) {
        if (this[i] && typeof this[i] == "object") {
            newObj[i] = this[i].clone();
        }
        else
        {
            newObj[i] = this[i];
        }
    }
    return newObj;
}; 

Object.defineProperty( Object.prototype, "clone", {value: clone, enumerable: false});
60
Zibri

Ich weiß, dass dies ein alter Beitrag ist, aber ich dachte, das könnte der nächsten Person, die dahinter stolpert, helfen.

Solange Sie keinem Objekt ein Objekt zuweisen, behält es keine Referenz im Speicher. Um ein Objekt zu erstellen, das Sie für andere Objekte freigeben möchten, müssen Sie eine Fabrik wie folgt erstellen:

var a = function(){
    return {
        father:'zacharias'
    };
},
b = a(),
c = a();
c.father = 'johndoe';
alert(b.father);
53
Joe

Cloning ein Objekt war in JS immer ein Problem, aber vor ES6 ging es um alles. Ich schreibe im Folgenden verschiedene Möglichkeiten zum Kopieren eines Objekts in JavaScript auf. Stellen Sie sich vor, Sie haben das Objekt unten und möchten eine tiefe Kopie davon haben:

var obj = {a:1, b:2, c:3, d:4};

Es gibt einige Möglichkeiten, dieses Objekt zu kopieren, ohne den Ursprung zu ändern:

1) ES5 +, Verwenden einer einfachen Funktion, um die Kopie für Sie auszuführen:

function deepCopyObj(obj) {
    if (null == obj || "object" != typeof obj) return obj;
    if (obj instanceof Date) {
        var copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }
    if (obj instanceof Array) {
        var copy = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            copy[i] = cloneSO(obj[i]);
        }
        return copy;
    }
    if (obj instanceof Object) {
        var copy = {};
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = cloneSO(obj[attr]);
        }
        return copy;
    }
    throw new Error("Unable to copy obj this object.");
}

2) ES5 + mit JSON.parse und JSON.stringify.

var  deepCopyObj = JSON.parse(JSON.stringify(obj));

3) AngularJs: 

var  deepCopyObj = angular.copy(obj);

4) jQuery: 

var deepCopyObj = jQuery.extend(true, {}, obj);

5) UnderscoreJs & Loadash: 

var deepCopyObj = _.cloneDeep(obj); //latest version UndescoreJs makes shallow copy

Hoffe diese Hilfe ... 

52
Alireza

Es gibt eine Bibliothek (genannt "Klon") , die das ganz gut macht. Es bietet das vollständigste rekursive Klonen/Kopieren beliebiger Objekte, die mir bekannt sind. Es unterstützt auch Zirkelverweise, die von den anderen Antworten noch nicht behandelt werden.

Sie können auch finden Sie unter npm . Es kann sowohl für den Browser als auch für Node.js verwendet werden.

Hier ist ein Beispiel, wie man es benutzt:

Installiere es mit

npm install clone

oder packen Sie es mit Ender .

ender build clone [...]

Sie können den Quellcode auch manuell herunterladen.

Dann können Sie es in Ihrem Quellcode verwenden.

var clone = require('clone');

var a = { foo: { bar: 'baz' } };  // inital value of a
var b = clone(a);                 // clone a -> b
a.foo.bar = 'foo';                // change a

console.log(a);                   // { foo: { bar: 'foo' } }
console.log(b);                   // { foo: { bar: 'baz' } }

(Haftungsausschluss: Ich bin der Autor der Bibliothek.)

52
pvorb

Wenn Sie es verwenden, verfügt die Bibliothek Underscore.js über eine Klon - Methode.

var newObject = _.clone(oldObject);
48
itsadok

Hier ist eine Version von ConroyPs Antwort, die auch dann funktioniert, wenn der Konstruktor die erforderlichen Parameter hat:

//If Object.create isn't already defined, we just do the simple shim,
//without the second argument, since that's all we need here
var object_create = Object.create;
if (typeof object_create !== 'function') {
    object_create = function(o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}

function deepCopy(obj) {
    if(obj == null || typeof(obj) !== 'object'){
        return obj;
    }
    //make sure the returned object has the same prototype as the original
    var ret = object_create(obj.constructor.prototype);
    for(var key in obj){
        ret[key] = deepCopy(obj[key]);
    }
    return ret;
}

Diese Funktion ist auch in meiner simpleoo library verfügbar.

Bearbeiten:

Hier ist eine robustere Version (dank Justin McCandless werden jetzt auch zyklische Referenzen unterstützt):

/**
 * Deep copy an object (make copies of all its object properties, sub-properties, etc.)
 * An improved version of http://keithdevens.com/weblog/archive/2007/Jun/07/javascript.clone
 * that doesn't break if the constructor has required parameters
 * 
 * It also borrows some code from http://stackoverflow.com/a/11621004/560114
 */ 
function deepCopy(src, /* INTERNAL */ _visited, _copiesVisited) {
    if(src === null || typeof(src) !== 'object'){
        return src;
    }

    //Honor native/custom clone methods
    if(typeof src.clone == 'function'){
        return src.clone(true);
    }

    //Special cases:
    //Date
    if(src instanceof Date){
        return new Date(src.getTime());
    }
    //RegExp
    if(src instanceof RegExp){
        return new RegExp(src);
    }
    //DOM Element
    if(src.nodeType && typeof src.cloneNode == 'function'){
        return src.cloneNode(true);
    }

    // Initialize the visited objects arrays if needed.
    // This is used to detect cyclic references.
    if (_visited === undefined){
        _visited = [];
        _copiesVisited = [];
    }

    // Check if this object has already been visited
    var i, len = _visited.length;
    for (i = 0; i < len; i++) {
        // If so, get the copy we already made
        if (src === _visited[i]) {
            return _copiesVisited[i];
        }
    }

    //Array
    if (Object.prototype.toString.call(src) == '[object Array]') {
        //[].slice() by itself would soft clone
        var ret = src.slice();

        //add it to the visited array
        _visited.Push(src);
        _copiesVisited.Push(ret);

        var i = ret.length;
        while (i--) {
            ret[i] = deepCopy(ret[i], _visited, _copiesVisited);
        }
        return ret;
    }

    //If we've reached here, we have a regular object

    //make sure the returned object has the same prototype as the original
    var proto = (Object.getPrototypeOf ? Object.getPrototypeOf(src): src.__proto__);
    if (!proto) {
        proto = src.constructor.prototype; //this line would probably only be reached by very old browsers 
    }
    var dest = object_create(proto);

    //add this object to the visited array
    _visited.Push(src);
    _copiesVisited.Push(dest);

    for (var key in src) {
        //Note: this does NOT preserve ES5 property attributes like 'writable', 'enumerable', etc.
        //For an example of how this could be modified to do so, see the singleMixin() function
        dest[key] = deepCopy(src[key], _visited, _copiesVisited);
    }
    return dest;
}

//If Object.create isn't already defined, we just do the simple shim,
//without the second argument, since that's all we need here
var object_create = Object.create;
if (typeof object_create !== 'function') {
    object_create = function(o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}
36
Matt Browne

Im Folgenden werden zwei Instanzen desselben Objekts erstellt. Ich habe es gefunden und benutze es derzeit. Es ist einfach und leicht zu bedienen.

var objToCreate = JSON.parse(JSON.stringify(cloneThis));
31
nathan rogers

Tiefes Kopieren von Objekten in JavaScript (ich denke, das Beste und das Einfachste)

1. JSON.parse verwenden (JSON.stringify (object));

var obj = { 
  a: 1,
  b: { 
    c: 2
  }
}
var newObj = JSON.parse(JSON.stringify(obj));
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 2 } } 

2.Verwendete erstellte Methode

function cloneObject(obj) {
    var clone = {};
    for(var i in obj) {
        if(obj[i] != null &&  typeof(obj[i])=="object")
            clone[i] = cloneObject(obj[i]);
        else
            clone[i] = obj[i];
    }
    return clone;
}

var obj = { 
  a: 1,
  b: { 
    c: 2
  }
}
var newObj = cloneObject(obj);
obj.b.c = 20;

console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 2 } } 

3. Verwenden von Lo-Dash's _.cloneDeep link lodash

var obj = { 
  a: 1,
  b: { 
    c: 2
  }
}

var newObj = _.cloneDeep(obj);
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 2 } } 

4. Object.assign () -Methode verwenden

var obj = { 
  a: 1,
  b: 2
}

var newObj = _.clone(obj);
obj.b = 20;
console.log(obj); // { a: 1, b: 20 }
console.log(newObj); // { a: 1, b: 2 }  

ABER FALSCH, WENN

var obj = { 
  a: 1,
  b: { 
    c: 2
  }
}

var newObj = Object.assign({}, obj);
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 20 } } --> WRONG
// Note: Properties on the prototype chain and non-enumerable properties cannot be copied.

5.Untererscore.js verwenden _.clone link Underscore.js

var obj = { 
  a: 1,
  b: 2
}

var newObj = _.clone(obj);
obj.b = 20;
console.log(obj); // { a: 1, b: 20 }
console.log(newObj); // { a: 1, b: 2 }  

ABER FALSCH, WENN

var obj = { 
  a: 1,
  b: { 
    c: 2
  }
}

var newObj = _.cloneDeep(obj);
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 20 } } --> WRONG
// (Create a shallow-copied clone of the provided plain object. Any nested objects or arrays will be copied by reference, not duplicated.)

Referenzmedium.com

JSBEN.CH Performance Benchmarking Playground 1 ~ 3 http://jsben.ch/KVQLd Performance Deep copying objects in JavaScript

28
TinhNQ

Lodash hat eine Nice _.cloneDeep (value) Methode:

var objects = [{ 'a': 1 }, { 'b': 2 }];

var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false
23
opensas

Crockford schlägt vor (und ich bevorzuge), diese Funktion zu verwenden:

function object(o) {
    function F() {}
    F.prototype = o;
    return new F();
}

var newObject = object(oldObject);

Es ist knapp, funktioniert wie erwartet und Sie brauchen keine Bibliothek.


BEARBEITEN:

Dies ist ein Polyfill für Object.create, daher können Sie dies auch verwenden.

var newObject = Object.create(oldObject);

HINWEIS: Wenn Sie einige davon verwenden, können Probleme mit der Iteration auftreten, die hasOwnProperty verwenden. Weil create ein neues leeres Objekt erstellt, das oldObject erbt. Es ist jedoch immer noch nützlich und praktisch, um Objekte zu klonen.

Zum Beispiel wenn oldObject.a = 5;

newObject.a; // is 5

aber:

oldObject.hasOwnProperty(a); // is true
newObject.hasOwnProperty(a); // is false
23
Chris Broski
function clone(obj)
 { var clone = {};
   clone.prototype = obj.prototype;
   for (property in obj) clone[property] = obj[property];
   return clone;
 }
22
Mark Cidade

Flacher Einliner ( ECMAScript 5th Edition ):

var Origin = { foo : {} };
var copy = Object.keys(Origin).reduce(function(c,k){c[k]=Origin[k];return c;},{});

console.log(Origin, copy);
console.log(Origin == copy); // false
console.log(Origin.foo == copy.foo); // true

Ein flacher Exemplar ( ECMAScript 6. Ausgabe , 2015):

var Origin = { foo : {} };
var copy = Object.assign({}, Origin);

console.log(Origin, copy);
console.log(Origin == copy); // false
console.log(Origin.foo == copy.foo); // true
20
Maël Nison

Nur weil ich AngularJS nicht gesehen und gedacht habe, dass die Leute vielleicht wissen wollen.

angular.copy bietet auch eine Methode zum tiefen Kopieren von Objekten und Arrays.

17
Dan Atkinson

Es scheint noch keinen idealen Deep-Clone-Operator für Array-ähnliche Objekte zu geben. Wie der folgende Code veranschaulicht, wandelt der jQuery-Cloner von John Resig Arrays mit nicht numerischen Eigenschaften in Objekte um, die keine Arrays sind, und der JSON-Cloner von RegDwight löscht die nicht-numerischen Eigenschaften. Die folgenden Tests veranschaulichen diese Punkte in mehreren Browsern:

function jQueryClone(obj) {
   return jQuery.extend(true, {}, obj)
}

function JSONClone(obj) {
   return JSON.parse(JSON.stringify(obj))
}

var arrayLikeObj = [[1, "a", "b"], [2, "b", "a"]];
arrayLikeObj.names = ["m", "n", "o"];
var JSONCopy = JSONClone(arrayLikeObj);
var jQueryCopy = jQueryClone(arrayLikeObj);

alert("Is arrayLikeObj an array instance?" + (arrayLikeObj instanceof Array) +
      "\nIs the jQueryClone an array instance? " + (jQueryCopy instanceof Array) +
      "\nWhat are the arrayLikeObj names? " + arrayLikeObj.names +
      "\nAnd what are the JSONClone names? " + JSONCopy.names)
16
Page Notes

Ich habe zwei gute Antworten, je nachdem, ob Sie ein "einfaches altes JavaScript-Objekt" klonen möchten oder nicht.

Nehmen wir auch an, dass Sie einen vollständigen Klon ohne Prototypreferenzen auf das Quellobjekt erstellen möchten. Wenn Sie nicht an einem vollständigen Klon interessiert sind, können Sie viele der Object.clone () - Routinen verwenden, die in einigen anderen Antworten enthalten sind (Crockfords Muster).

Für einfache alte JavaScript-Objekte ist ein bewährter Weg, ein Objekt in modernen Laufzeiten zu klonen, ganz einfach:

var clone = JSON.parse(JSON.stringify(obj));

Beachten Sie, dass das Quellobjekt ein reines JSON-Objekt sein muss. Das heißt, alle geschachtelten Eigenschaften müssen Skalare sein (wie boolean, string, array, object usw.). Funktionen oder spezielle Objekte wie RegExp oder Date werden nicht geklont.

Ist es effizient? Oh Ja. Wir haben alle möglichen Klonmethoden ausprobiert und dies funktioniert am besten. Ich bin sicher, ein Ninja könnte eine schnellere Methode heraufbeschwören. Ich vermute aber, dass wir über geringfügige Gewinne sprechen.

Dieser Ansatz ist einfach und leicht zu implementieren. Wickeln Sie es in eine Komfortfunktion und wenn Sie wirklich etwas Gewinn herausholen müssen, machen Sie es zu einem späteren Zeitpunkt.

Für nicht-einfache JavaScript-Objekte gibt es keine wirklich einfache Antwort. In der Tat kann es nicht wegen der dynamischen Natur der JavaScript-Funktionen und des inneren Objektzustands geben. Um eine JSON-Struktur mit Funktionen zu klonen, müssen Sie diese Funktionen und ihren inneren Kontext neu erstellen. JavaScript hat dafür einfach keine standardisierte Methode.

Der korrekte Weg, dies noch einmal zu tun, ist eine bequeme Methode, die Sie innerhalb Ihres Codes deklarieren und wiederverwenden. Die Komfortmethode kann mit einem gewissen Verständnis Ihrer eigenen Objekte ausgestattet werden, sodass Sie sicherstellen können, dass das Diagramm innerhalb des neuen Objekts ordnungsgemäß neu erstellt wird.

Wir sind unsere eigenen, aber der beste allgemeine Ansatz, den ich je gesehen habe, wird hier behandelt:

http://davidwalsh.name/javascript-clone

Das ist die richtige Idee. Der Autor (David Walsh) hat das Klonen allgemeiner Funktionen auskommentiert. Dies können Sie je nach Anwendungsfall wählen.

Die Grundidee ist, dass Sie die Instantiierung Ihrer Funktionen (oder sozusagen prototypischen Klassen) auf Typebene speziell behandeln müssen. Hier hat er einige Beispiele für RegExp und Date gegeben.

Dieser Code ist nicht nur kurz, sondern auch lesbar. Es ist ziemlich einfach zu erweitern.

Ist das effizient? Oh Ja. Da das Ziel darin besteht, einen echten Klon mit tiefen Kopien zu erstellen, müssen Sie die Elemente des Quellobjektdiagramms durchlaufen. Mit diesem Ansatz können Sie genau festlegen, welche untergeordneten Elemente behandelt werden sollen und wie benutzerdefinierte Typen manuell behandelt werden.

Hier bitteschön. Zwei Ansätze. Beide sind meiner Ansicht nach effizient.

15

Dies ist im Allgemeinen nicht die effizienteste Lösung, aber es macht, was ich brauche. Einfache Testfälle unten ...

function clone(obj, clones) {
    // Makes a deep copy of 'obj'. Handles cyclic structures by
    // tracking cloned obj's in the 'clones' parameter. Functions 
    // are included, but not cloned. Functions members are cloned.
    var new_obj,
        already_cloned,
        t = typeof obj,
        i = 0,
        l,
        pair; 

    clones = clones || [];

    if (obj === null) {
        return obj;
    }

    if (t === "object" || t === "function") {

        // check to see if we've already cloned obj
        for (i = 0, l = clones.length; i < l; i++) {
            pair = clones[i];
            if (pair[0] === obj) {
                already_cloned = pair[1];
                break;
            }
        }

        if (already_cloned) {
            return already_cloned; 
        } else {
            if (t === "object") { // create new object
                new_obj = new obj.constructor();
            } else { // Just use functions as is
                new_obj = obj;
            }

            clones.Push([obj, new_obj]); // keep track of objects we've cloned

            for (key in obj) { // clone object members
                if (obj.hasOwnProperty(key)) {
                    new_obj[key] = clone(obj[key], clones);
                }
            }
        }
    }
    return new_obj || obj;
}

Zyklischer Array-Test ...

a = []
a.Push("b", "c", a)
aa = clone(a)
aa === a //=> false
aa[2] === a //=> false
aa[2] === a[2] //=> false
aa[2] === aa //=> true

Funktionstest...

f = new Function
f.a = a
ff = clone(f)
ff === f //=> true
ff.a === a //=> false
13
neatonk

AngularJS

Wenn Sie Winkel verwenden, können Sie dies auch tun

var newObject = angular.copy(oldObject);
11
azerafati

Ich stimme der Antwort mit den größten Stimmen hier nicht zu. Ein Recursive Deep Clone ist viel schneller als der JSON.parse (JSON.stringify (obj)) -Ansatz. 

Und hier ist die Funktion zum schnellen Nachschlagen:

function cloneDeep (o) {
  let newO
  let i

  if (typeof o !== 'object') return o

  if (!o) return o

  if (Object.prototype.toString.apply(o) === '[object Array]') {
    newO = []
    for (i = 0; i < o.length; i += 1) {
      newO[i] = cloneDeep(o[i])
    }
    return newO
  }

  newO = {}
  for (i in o) {
    if (o.hasOwnProperty(i)) {
      newO[i] = cloneDeep(o[i])
    }
  }
  return newO
}
10
prograhammer
// obj target object, vals source object
var setVals = function (obj, vals) {
    if (obj && vals) {
        for (var x in vals) {
            if (vals.hasOwnProperty(x)) {
                if (obj[x] && typeof vals[x] === 'object') {
                    obj[x] = setVals(obj[x], vals[x]);
                } else {
                    obj[x] = vals[x];
                }
            }
        }
    }
    return obj;
};
10
Dima

Für die Personen, die die JSON.parse(JSON.stringify(obj))-Version verwenden möchten, ohne die Date-Objekte zu verlieren, können Sie das second-Argument der parse-Methode verwenden, um die Zeichenfolgen zurück in Date zu konvertieren:

function clone(obj) {
  var regExp = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
  return JSON.parse(JSON.stringify(x), function(k, v) {
    if (typeof v === 'string' && regExp.test(v))
      return new Date(v);
    return v;
  });
}
8
Buzinas

Hier ist eine umfassende clone () -Methode, die jedes JavaScript-Objekt klonen kann. Es behandelt fast alle Fälle:

function clone(src, deep) {

    var toString = Object.prototype.toString;
    if (!src && typeof src != "object") {
        // Any non-object (Boolean, String, Number), null, undefined, NaN
        return src;
    }

    // Honor native/custom clone methods
    if (src.clone && toString.call(src.clone) == "[object Function]") {
        return src.clone(deep);
    }

    // DOM elements
    if (src.nodeType && toString.call(src.cloneNode) == "[object Function]") {
        return src.cloneNode(deep);
    }

    // Date
    if (toString.call(src) == "[object Date]") {
        return new Date(src.getTime());
    }

    // RegExp
    if (toString.call(src) == "[object RegExp]") {
        return new RegExp(src);
    }

    // Function
    if (toString.call(src) == "[object Function]") {

        //Wrap in another method to make sure == is not true;
        //Note: Huge performance issue due to closures, comment this :)
        return (function(){
            src.apply(this, arguments);
        });
    }

    var ret, index;
    //Array
    if (toString.call(src) == "[object Array]") {
        //[].slice(0) would soft clone
        ret = src.slice();
        if (deep) {
            index = ret.length;
            while (index--) {
                ret[index] = clone(ret[index], true);
            }
        }
    }
    //Object
    else {
        ret = src.constructor ? new src.constructor() : {};
        for (var prop in src) {
            ret[prop] = deep
                ? clone(src[prop], true)
                : src[prop];
        }
    }
    return ret;
};
8
user1547016

Normalerweise benutze ich var newObj = JSON.parse( JSON.stringify(oldObje) );, aber hier ist der richtige Weg:

var o = {};

var oo = Object.create(o);

(o === oo); // => false

Beobachten Sie ältere Browser!

6
Cody

Ich verwende die Klonbibliothek npm. Anscheinend funktioniert es auch im Browser.

https://www.npmjs.com/package/clone

let a = clone(b)
6
user3071643

Nur wenn Sie ECMAScript 6 oder Transpiler verwenden können.

Eigenschaften:

  • Löst beim Kopieren keinen Getter/Setter aus.
  • Erhält Getter/Setter.
  • Erhält Prototypinformationen.
  • Funktioniert mit den Schreibstilen object-literal und funktionalOO .

Code:

function clone(target, source){

    for(let key in source){

        // Use getOwnPropertyDescriptor instead of source[key] to prevent from trigering setter/getter.
        let descriptor = Object.getOwnPropertyDescriptor(source, key);
        if(descriptor.value instanceof String){
            target[key] = new String(descriptor.value);
        }
        else if(descriptor.value instanceof Array){
            target[key] = clone([], descriptor.value);
        }
        else if(descriptor.value instanceof Object){
            let prototype = Reflect.getPrototypeOf(descriptor.value);
            let cloneObject = clone({}, descriptor.value);
            Reflect.setPrototypeOf(cloneObject, prototype);
            target[key] = cloneObject;
        }
        else {
            Object.defineProperty(target, key, descriptor);
        }
    }
    let prototype = Reflect.getPrototypeOf(source);
    Reflect.setPrototypeOf(target, prototype);
    return target;
}
6
andrew

Klonen eines Objekts mit dem heutigen JavaScript: ECMAScript 2015 (früher als ECMAScript 6 bekannt)

var original = {a: 1};

// Method 1: New object with original assigned.
var copy1 = Object.assign({}, original);

// Method 2: New object with spread operator assignment.
var copy2 = {...original};

Alte Browser unterstützen möglicherweise nicht ECMAScript 2015. Eine gängige Lösung ist die Verwendung eines JavaScript-zu-JavaScript-Compilers wie Babel zur Ausgabe einer ECMAScript 5 - Version Ihres JavaScript-Codes.

Wie wies @ jim-hall darauf hin , , ist dies nur eine flache Kopie. Eigenschaften von Eigenschaften werden als Referenz kopiert: Wenn Sie eine Eigenschaft ändern, wird der Wert in dem anderen Objekt/der anderen Instanz geändert.

6
Barry Staes

Einzeilige ECMAScript 6-Lösung (spezielle Objekttypen wie Date/Regex werden nicht behandelt):

const clone = (o) =>
  typeof o === 'object' && o !== null ?      // only clone objects
  (Array.isArray(o) ?                        // if cloning an array
    o.map(e => clone(e)) :                   // clone each of its elements
    Object.keys(o).reduce(                   // otherwise reduce every key in the object
      (r, k) => (r[k] = clone(o[k]), r), {}  // and save its cloned value into a new object
    )
  ) :
  o;                                         // return non-objects as is

var x = {
  nested: {
    name: 'test'
  }
};

var y = clone(x);

console.log(x.nested !== y.nested);

5
Shishir Arora

Ich bin zu spät, um diese Frage zu beantworten, aber ich habe eine andere Möglichkeit, das Objekt zu klonen:

   function cloneObject(obj) {
        if (obj === null || typeof(obj) !== 'object')
            return obj;
        var temp = obj.constructor(); // changed
        for (var key in obj) {
            if (Object.prototype.hasOwnProperty.call(obj, key)) {
                obj['isActiveClone'] = null;
                temp[key] = cloneObject(obj[key]);
                delete obj['isActiveClone'];
            }
        }
        return temp;
    }



var b = cloneObject({"a":1,"b":2});   // calling

das ist viel besser und schneller als:

var a = {"a":1,"b":2};
var b = JSON.parse(JSON.stringify(a));  

und

var a = {"a":1,"b":2};

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

Ich habe den Code mit einer Benchmark versehen und Sie können die Ergebnisse testen hier :

und teilen Sie die Ergebnisse:  enter image description here Referenzen: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty

5
Mayur Agarwal

Lodash hat eine Funktion, die das für Sie so behandelt.

var foo = {a: 'a', b: {c:'d', e: {f: 'g'}}};

var bar = _.cloneDeep(foo);
// bar = {a: 'a', b: {c:'d', e: {f: 'g'}}} 

Lesen Sie die Dokumente hier .

5
Daniel Barde

Dies ist die schnellste Methode, die ich erstellt habe und die den Prototyp nicht verwendet. Daher wird hasOwnProperty im neuen Objekt beibehalten.

Die Lösung besteht darin, die Eigenschaften der obersten Ebene des ursprünglichen Objekts zu durchlaufen, zwei Kopien zu erstellen, jede Eigenschaft aus dem Original zu löschen, das ursprüngliche Objekt zurückzusetzen und die neue Kopie zurückzugeben. Es muss nur so oft wiederholt werden, wie die Eigenschaften der obersten Ebene. Dadurch werden alle if-Bedingungen gespeichert, um zu prüfen, ob jede Eigenschaft eine Funktion, ein Objekt, eine Zeichenfolge usw. ist. Jede untergeordnete Eigenschaft muss nicht durchlaufen werden.

Der einzige Nachteil ist, dass das ursprüngliche Objekt mit dem ursprünglich erstellten Namespace bereitgestellt werden muss, um es zurückzusetzen.

copyDeleteAndReset:function(namespace,strObjName){
    var obj = namespace[strObjName],
    objNew = {},objOrig = {};
    for(i in obj){
        if(obj.hasOwnProperty(i)){
            objNew[i] = objOrig[i] = obj[i];
            delete obj[i];
        }
    }
    namespace[strObjName] = objOrig;
    return objNew;
}

var namespace = {};
namespace.objOrig = {
    '0':{
        innerObj:{a:0,b:1,c:2}
    }
}

var objNew = copyDeleteAndReset(namespace,'objOrig');
objNew['0'] = 'NEW VALUE';

console.log(objNew['0']) === 'NEW VALUE';
console.log(namespace.objOrig['0']) === innerObj:{a:0,b:1,c:2};
4
Steve Tomlin

Der zukünftige Entwurf von ECMAScript 6 führt Object.assign ein, um Objekte zu klonen. Beispielcode wäre:

var obj1 = { a: true, b: 1 };
var obj2 = Object.assign(obj1);
console.log(obj2); // { a: true, b: 1 }

Zum Zeitpunkt des Schreibens ist die Unterstützung in Browsern auf Firefox 34 beschränkt es ist also noch nicht im Produktionscode verwendbar (sofern Sie nicht gerade eine Firefox-Erweiterung schreiben).

4

ES 2017 Beispiel:

let objectToCopy = someObj;
let copyOfObject = {};
Object.defineProperties(copyOfObject, Object.getOwnPropertyDescriptors(objectToCopy));
// copyOfObject will now be the same as objectToCopy
4
codeMonkey

Was ist mit dem asynchronen Klonen von Objekten, das von einer Promise durchgeführt wird?

async function clone(thingy /**/)
{
    if(thingy instanceof Promise)
    {
        throw Error("This function cannot clone Promises.");
    }
    return thingy;
}

In JavaScript können Sie Ihre deepCopy-Methode wie schreiben 

function deepCopy(src) {
  let target = Array.isArray(src) ? [] : {};
  for (let prop in src) {
    let value = src[prop];
    if(value && typeof value === 'object') {
      target[prop] = deepCopy(value);
  } else {
      target[prop] = value;
  }
 }
    return target;
}
3
chandan gupta

Es gibt so viele Möglichkeiten, dies zu erreichen, aber wenn Sie dies ohne Bibliothek tun möchten, können Sie Folgendes verwenden:

const cloneObject = (oldObject) => {
  let newObject = oldObject;
  if (oldObject && typeof oldObject === 'object') {
    if(Array.isArray(oldObject)) {
      newObject = [];
    } else if (Object.prototype.toString.call(oldObject) === '[object Date]' && !isNaN(oldObject)) {
      newObject = new Date(oldObject.getTime());
    } else {
      newObject = {};
      for (let i in oldObject) {
        newObject[i] = cloneObject(oldObject[i]);
      }
    }

  }
  return newObject;
}

Lass mich wissen was du denkst.

3
shobhit1

Dies ist meine Version von Object Cloner. Dies ist eine eigenständige Version der jQuery-Methode mit nur wenigen Anpassungen und Anpassungen. Schauen Sie sich die Geige an. Ich habe viel jQuery verwendet, bis ich merkte, dass ich meistens nur diese Funktion verwenden würde.

Die Verwendung ist die gleiche wie in der jQuery-API beschrieben:

  • Nicht tiefer Klon: extend(object_dest, object_source);
  • Tiefen Klon: extend(true, object_dest, object_source);

Eine zusätzliche Funktion wird verwendet, um zu definieren, ob das Objekt zum Klonen geeignet ist.

/**
 * This is a quasi clone of jQuery's extend() function.
 * by Romain WEEGER for wJs library - www.wexample.com
 * @returns {*|{}}
 */
function extend() {
    // Make a copy of arguments to avoid JavaScript inspector hints.
    var to_add, name, copy_is_array, clone,

    // The target object who receive parameters
    // form other objects.
    target = arguments[0] || {},

    // Index of first argument to mix to target.
    i = 1,

    // Mix target with all function arguments.
    length = arguments.length,

    // Define if we merge object recursively.
    deep = false;

    // Handle a deep copy situation.
    if (typeof target === 'boolean') {
        deep = target;

        // Skip the boolean and the target.
        target = arguments[ i ] || {};

        // Use next object as first added.
        i++;
    }

    // Handle case when target is a string or something (possible in deep copy)
    if (typeof target !== 'object' && typeof target !== 'function') {
        target = {};
    }

    // Loop trough arguments.
    for (false; i < length; i += 1) {

        // Only deal with non-null/undefined values
        if ((to_add = arguments[ i ]) !== null) {

            // Extend the base object.
            for (name in to_add) {

                // We do not wrap for loop into hasOwnProperty,
                // to access to all values of object.
                // Prevent never-ending loop.
                if (target === to_add[name]) {
                    continue;
                }

                // Recurse if we're merging plain objects or arrays.
                if (deep && to_add[name] && (is_plain_object(to_add[name]) || (copy_is_array = Array.isArray(to_add[name])))) {
                    if (copy_is_array) {
                        copy_is_array = false;
                        clone = target[name] && Array.isArray(target[name]) ? target[name] : [];
                    }
                    else {
                        clone = target[name] && is_plain_object(target[name]) ? target[name] : {};
                    }

                    // Never move original objects, clone them.
                    target[name] = extend(deep, clone, to_add[name]);
                }

                // Don't bring in undefined values.
                else if (to_add[name] !== undefined) {
                    target[name] = to_add[name];
                }
            }
        }
    }
    return target;
}

/**
 * Check to see if an object is a plain object
 * (created using "{}" or "new Object").
 * Forked from jQuery.
 * @param obj
 * @returns {boolean}
 */
function is_plain_object(obj) {
    // Not plain objects:
    // - Any object or value whose internal [[Class]] property is not "[object Object]"
    // - DOM nodes
    // - window
    if (obj === null || typeof obj !== "object" || obj.nodeType || (obj !== null && obj === obj.window)) {
        return false;
    }
    // Support: Firefox <20
    // The try/catch suppresses exceptions thrown when attempting to access
    // the "constructor" property of certain Host objects, i.e. |window.location|
    // https://bugzilla.mozilla.org/show_bug.cgi?id=814622
    try {
        if (obj.constructor && !this.hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf")) {
            return false;
        }
    }
    catch (e) {
        return false;
    }

    // If the function hasn't returned already, we're confident that
    // |obj| is a plain object, created by {} or constructed with new Object
    return true;
}
3
weeger

Ich denke, dass dies die beste Lösung ist, wenn Sie Ihren Algorithmus zum Klonen von Objekten verallgemeinern möchten.
Sie kann mit oder ohne jQuery verwendet werden. Ich empfehle jedoch, die Erweiterungsmethode von jQuery auszuschließen, wenn Sie möchten, dass das geklonte Objekt dieselbe "Klasse" wie die ursprüngliche hat.

function clone(obj){
    if(typeof(obj) == 'function')//it's a simple function
        return obj;
    //of it's not an object (but could be an array...even if in javascript arrays are objects)
    if(typeof(obj) !=  'object' || obj.constructor.toString().indexOf('Array')!=-1)
        if(JSON != undefined)//if we have the JSON obj
            try{
                return JSON.parse(JSON.stringify(obj));
            }catch(err){
                return JSON.parse('"'+JSON.stringify(obj)+'"');
            }
        else
            try{
                return eval(uneval(obj));
            }catch(err){
                return eval('"'+uneval(obj)+'"');
            }
    // I used to rely on jQuery for this, but the "extend" function returns
    //an object similar to the one cloned,
    //but that was not an instance (instanceof) of the cloned class
    /*
    if(jQuery != undefined)//if we use the jQuery plugin
        return jQuery.extend(true,{},obj);
    else//we recursivley clone the object
    */
    return (function _clone(obj){
        if(obj == null || typeof(obj) != 'object')
            return obj;
        function temp () {};
        temp.prototype = obj;
        var F = new temp;
        for(var key in obj)
            F[key] = clone(obj[key]);
        return F;
    })(obj);            
}
3
gion_13

Es gibt viele Antworten, aber keine davon ergab den gewünschten Effekt, den ich brauchte. Ich wollte die Macht der tiefen Kopie von jQuery nutzen ... Wenn es jedoch in ein Array läuft, wird der Verweis einfach auf das Array kopiert und die darin enthaltenen Elemente werden tief kopiert. Um dies zu umgehen, habe ich eine kleine rekursive Funktion erstellt, die automatisch ein neues Array erstellt. 

(Es wird sogar nach kendo.data.ObservableArray gesucht, wenn Sie es möchten! Stellen Sie jedoch sicher, dass Sie kendo.observable (newItem) aufrufen, wenn die Arrays wieder beobachtbar sein sollen.) 

Um ein vorhandenes Objekt vollständig zu kopieren, führen Sie einfach Folgendes aus:

var newItem = jQuery.extend(true, {}, oldItem);
createNewArrays(newItem);


function createNewArrays(obj) {
    for (var prop in obj) {
        if ((kendo != null && obj[prop] instanceof kendo.data.ObservableArray) || obj[prop] instanceof Array) {
            var copy = [];
            $.each(obj[prop], function (i, item) {
                var newChild = $.extend(true, {}, item);
                createNewArrays(newChild);
                copy.Push(newChild);
            });
            obj[prop] = copy;
        }
    }
}
3
Daniel Lorenz

Hier ist meine Methode zum tiefen Klonen eines Objekts mit ES2015 Standardwert und Spread-Operator

 const makeDeepCopy = (obj, copy = {}) => {
  for (let item in obj) {
    if (typeof obj[item] === 'object') {
      makeDeepCopy(obj[item], copy)
    }
    if (obj.hasOwnProperty(item)) {
      copy = {
        ...obj
      }
    }
  }
  return copy
}

const testObj = {
  "type": "object",
  "properties": {
    "userId": {
      "type": "string",
      "chance": "guid"
    },
    "emailAddr": {
      "type": "string",
      "chance": {
        "email": {
          "domain": "fake.com"
        }
      },
      "pattern": "[email protected]"
    }
  },
  "required": [
    "userId",
    "emailAddr"
  ]
}

const makeDeepCopy = (obj, copy = {}) => {
  for (let item in obj) {
    if (typeof obj[item] === 'object') {
      makeDeepCopy(obj[item], copy)
    }
    if (obj.hasOwnProperty(item)) {
      copy = {
        ...obj
      }
    }
  }
  return copy
}

console.log(makeDeepCopy(testObj))

3
Julez

Ohne die prototypische Vererbung zu berühren, können Sie einsame Objekte und Arrays wie folgt vertiefen;

function objectClone(o){
  var ot = Array.isArray(o);
  return o !== null && typeof o === "object" ? Object.keys(o)
                                                     .reduce((r,k) => o[k] !== null && typeof o[k] === "object" ? (r[k] = objectClone(o[k]),r)
                                                                                                                : (r[k] = o[k],r), ot ? [] : {})
                                             : o;
}
var obj = {a: 1, b: {c: 2, d: {e: 3, f: {g: 4, h: null}}}},
    arr = [1,2,[3,4,[5,6,[7]]]],
    nil = null,
  clobj = objectClone(obj),
  clarr = objectClone(arr),
  clnil = objectClone(nil);
console.log(clobj, obj === clobj);
console.log(clarr, arr === clarr);
console.log(clnil, nil === clnil);
clarr[2][2][2] = "seven";
console.log(arr, clarr);

2
Redu

Für eine flache Kopie gibt es eine großartige, einfache Methode, die im ECMAScript2018-Standard eingeführt wurde. Es beinhaltet die Verwendung von Spread Operator :

let obj = {a : "foo", b:"bar" , c:10 , d:true , e:[1,2,3] };

let objClone = { ...obj };

Ich habe es im Chrome-Browser getestet. Beide Objekte werden an unterschiedlichen Orten gespeichert. Wenn Sie also die untergeordneten Werte in einem der beiden Objekte ändern, ändert sich der andere nicht. Das Ändern eines Werts in e wirkt sich jedoch (im Beispiel) auf beide Kopien aus.

Diese Technik ist sehr einfach und unkompliziert. Ich halte dies für ein wahres Best Practice für diese Frage ein für alle Mal. 

2
Vikram K

Verwenden Sie Object.create(), um die prototype und die Unterstützung für instanceof abzurufen, und verwenden Sie eine for()-Schleife, um aufzählbare Schlüssel zu erhalten:

function cloneObject(source) {
    var key,value;
    var clone = Object.create(source);

    for (key in source) {
        if (source.hasOwnProperty(key) === true) {
            value = source[key];

            if (value!==null && typeof value==="object") {
                clone[key] = cloneObject(value);
            } else {
                clone[key] = value;
            }
        }
    }

    return clone;
}
2
Steven Vachon

class Handler {
  static deepCopy (obj) {
    if (Object.prototype.toString.call(obj) === '[object Array]') {
      const result = [];
      
      for (let i = 0, len = obj.length; i < len; i++) {
        result[i] = Handler.deepCopy(obj[i]);
      }
      return result;
    } else if (Object.prototype.toString.call(obj) === '[object Object]') {
      const result = {};
      for (let prop in obj) {
        result[prop] = Handler.deepCopy(obj[prop]);
      }
      return result;
    }
    return obj;
  }
}

2
Ihor Pavlyk

Benötigt neue ish-Browser, aber ...

Lassen Sie uns das native Objekt erweitern und erhalten Sie eine real .extend();

Object.defineProperty(Object.prototype, 'extend', {
    enumerable: false,
    value: function(){
        var that = this;

        Array.prototype.slice.call(arguments).map(function(source){
            var props = Object.getOwnPropertyNames(source),
                i = 0, l = props.length,
                prop;

            for(; i < l; ++i){
                prop = props[i];

                if(that.hasOwnProperty(prop) && typeof(that[prop]) === 'object'){
                    that[prop] = that[prop].extend(source[prop]);
                }else{
                    Object.defineProperty(that, prop, Object.getOwnPropertyDescriptor(source, prop));
                }
            }
        });

        return this;
    }
});

Fügen Sie das einfach in einen beliebigen Code ein, der .extend () für ein Objekt verwendet.

Beispiel:

var obj1 = {
    node1: '1',
    node2: '2',
    node3: 3
};

var obj2 = {
    node1: '4',
    node2: 5,
    node3: '6'
};

var obj3 = ({}).extend(obj1, obj2);

console.log(obj3);
// Object {node1: "4", node2: 5, node3: "6"}
2
Tristian

2019 benutze ich:

deepCopy(object) {
  const getCircularReplacer = () => {
    const seen = new WeakSet();
    return (key, value) => {
      if(typeof value === 'object' && value !== null) {
        if(seen.has(value)) return;
        seen.add(value);
      }
      return value;
    };
  };
  return JSON.parse(JSON.stringify(object, getCircularReplacer()));
}

const theCopy = deepCopy(originalObject);

2

Da Rekursion für JavaScript einfach zu teuer ist und die meisten Antworten, die ich gefunden habe, Rekursion verwenden, während der JSON-Ansatz die nicht JSON-konvertierbaren Teile (Funktion usw.) überspringt. Also habe ich ein wenig recherchiert und diese Trampolin-Technik gefunden, um es zu vermeiden. Hier ist der Code:

/*
 * Trampoline to avoid recursion in JavaScript, see:
 *     http://www.integralist.co.uk/posts/js-recursion.html
 */
function trampoline() {
    var func = arguments[0];
    var args = [];
    for (var i = 1; i < arguments.length; i++) {
        args[i - 1] = arguments[i];
    }

    var currentBatch = func.apply(this, args);
    var nextBatch = [];

    while (currentBatch && currentBatch.length > 0) {
        currentBatch.forEach(function(eachFunc) {
            var ret = eachFunc();
            if (ret && ret.length > 0) {
                nextBatch = nextBatch.concat(ret);
            }
        });

        currentBatch = nextBatch;
        nextBatch = [];
    }
};

/*
 *  Deep clone an object using the trampoline technique.
 *
 *  @param target {Object} Object to clone
 *  @return {Object} Cloned object.
 */
function clone(target) {
    if (typeof target !== 'object') {
        return target;
    }
    if (target == null || Object.keys(target).length == 0) {
        return target;
    }

    function _clone(b, a) {
        var nextBatch = [];
        for (var key in b) {
            if (typeof b[key] === 'object' && b[key] !== null) {
                if (b[key] instanceof Array) {
                    a[key] = [];
                }
                else {
                    a[key] = {};
                }
                nextBatch.Push(_clone.bind(null, b[key], a[key]));
            }
            else {
                a[key] = b[key];
            }
        }
        return nextBatch;
    };

    var ret = target instanceof Array ? [] : {};
    (trampoline.bind(null, _clone))(target, ret);
    return ret;
};

Siehe auch diesen Gist: https://Gist.github.com/SeanOceanHu/7594cafbfab682f790eb

2
Bodhi Hu

Für spätere Referenz kann man diesen Code verwenden

ES6:

_clone: function(obj){
    let newObj = {};
    for(let i in obj){
        if(typeof(obj[i]) === 'object' && Object.keys(obj[i]).length){
            newObj[i] = clone(obj[i]);
        } else{
            newObj[i] = obj[i];
        }
    }
    return Object.assign({},newObj);
}

ES5:

function clone(obj){
let newObj = {};
for(let i in obj){
    if(typeof(obj[i]) === 'object' && Object.keys(obj[i]).length){
        newObj[i] = clone(obj[i]);
    } else{
        newObj[i] = obj[i];
    }
}
return Object.assign({},newObj);

}

Z.B 

var obj ={a:{b:1,c:3},d:4,e:{f:6}}
var xc = clone(obj);
console.log(obj); //{a:{b:1,c:3},d:4,e:{f:6}}
console.log(xc); //{a:{b:1,c:3},d:4,e:{f:6}}

xc.a.b = 90;
console.log(obj); //{a:{b:1,c:3},d:4,e:{f:6}}
console.log(xc); //{a:{b:90,c:3},d:4,e:{f:6}}
2
Ashutosh Jha

Object.assign({},sourceObj) klont das Objekt nur, wenn seine Eigenschaft keinen Referenztypschlüssel hat. Ex

obj={a:"lol",b:["yes","no","maybe"]}
clonedObj = Object.assign({},obj);

clonedObj.b.Push("skip")// changes will reflected to the actual obj as well because of its reference type.
obj.b //will also console => yes,no,maybe,skip

Damit ist auf diese Weise kein tiefes Klonen möglich.

Die beste Lösung, die funktioniert, ist

var obj = Json.stringify(yourSourceObj)
var cloned = Json.parse(obj);
2

Nach meiner Erfahrung übertrifft eine rekursive Version JSON.parse(JSON.stringify(obj)) bei weitem. Hier ist eine modernisierte rekursive Funktion für tiefere Objekte, die in eine einzige Zeile passen kann:

function deepCopy(obj) {
  return Object.keys(obj).reduce((v, d) => Object.assign(v, {
    [d]: (obj[d].constructor === Object) ? deepCopy(obj[d]) : obj[d]
  }), {});
}

Dies ist rund um 40-mal schneller als die JSON.parse...-Methode.

2
Parabolord

Es gibt drei verschiedene Möglichkeiten, Objekte in Javascript zu klonen.

1: Tiefes Kopieren mit Iteration

function iterationCopy(src) {
  let target = {};
  for (let prop in src) {
    if (src.hasOwnProperty(prop)) {
      target[prop] = src[prop];
    }
  }
  return target;
}
const source = {a:1, b:2, c:3};
const target = iterationCopy(source);
console.log(target); // {a:1, b:2, c:3}
// Check if clones it and not changing it
source.a = 'a';
console.log(source.a); // 'a'
console.log(target.a); // 1

Wie Sie sehen, funktioniert es!

Lassen Sie uns nun die Verfolgung auf die zweite Lösung beschränken, die zwar eleganter, aber auf die Verwendung beschränkter ist.

2: Konvertieren nach JSON und zurück

function jsonCopy(src) {
  return JSON.parse(JSON.stringify(src));
}
const source = {a:1, b:2, c:3};
const target = jsonCopy(source);
console.log(target); // {a:1, b:2, c:3}
// Check if clones it and not changing it
source.a = 'a';
console.log(source.a); // 'a'
console.log(target.a); // 1

Hinweis: Seien Sie vorsichtig bei der Verwendung dieser Methode, da Ihr Quellobjekt JSON-sicher sein MUSS. Daher ist möglicherweise eine Ausnahmebehandlung erforderlich, um die Sicherheit in Fällen zu gewährleisten, in denen das Quellobjekt nicht in JSON konvertiert werden kann.

3: Verwenden von Object.assign

Update: Diese Methode hat den Fehler, dass es nur eine flache Kopie macht. Dies bedeutet, dass verschachtelte Eigenschaften weiterhin als Referenz kopiert werden. Sei vorsichtig damit.

Dieser Weg ist der beste und sicherste, den ich persönlich in meinen Projekten verwende. Es nutzt eine integrierte statische Methode für das Object-Objekt und wird von der Sprache verwaltet und bereitgestellt. Also benutze diesen!

function bestCopyEver(src) {
  return Object.assign({}, src);
}
const source = {a:1, b:2, c:3};
const target = bestCopyEver(source);
console.log(target); // {a:1, b:2, c:3}
// Check if clones it and not changing it
source.a = 'a';
console.log(source.a); // 'a'
console.log(target.a); // 1
2
Kishan Patel

Dies ist eine Lösung mit Rekursion:

obj = {
  a: { b: { c: { d: ['1', '2'] } } },
  e: 'Saeid'
}
const Clone = function (obj) {
  
  const container = Array.isArray(obj) ? [] : {}
  const keys  = Object.keys(obj)
   
  for (let i = 0; i < keys.length; i++) {
    const key = keys[i]
    if(typeof obj[key] == 'object') {
      container[key] = Clone(obj[key])
    }
    else
      container[key] = obj[key].slice()
  }
  
  return container
}
 console.log(Clone(obj))

2
SAlidadi

wenn Sie feststellen, dass Sie diese Art von Dingen regelmäßig ausführen (z. B. Erstellen von Undo-Wiederherstellungsfunktionen), lohnt es sich, Immutable.js

const map1 = Immutable.fromJS( { a: 1, b: 2, c: { d: 3 } } );
const map2 = map1.setIn( [ 'c', 'd' ], 50 );

console.log( `${ map1.getIn( [ 'c', 'd' ] ) } vs ${ map2.getIn( [ 'c', 'd' ] ) }` ); // "3 vs 50"

https://codepen.io/anon/pen/OBpqNE?editors=1111

1
shunryu111

Durch das Durchsehen dieser langen Liste von Antworten wurden fast alle Lösungen abgedeckt, außer einer, die mir bekannt ist. Dies ist die Liste der Vanilla JS-Methoden zum tiefen Klonen eines Objekts.

  1. JSON.parse (JSON.stringify (obj));

  2. Durch history.state mit pushState oder replaceState

  3. Web Notifications API, dies hat jedoch den Nachteil, dass der Benutzer nach Berechtigungen gefragt wird.

  4. Führen Sie Ihre eigene rekursive Schleife durch das Objekt, um die einzelnen Ebenen zu kopieren.

  5. Die Antwort, die ich nicht gesehen habe -> ServiceWorkers verwenden. Die Nachrichten (Objekte), die zwischen der Seite und dem ServiceWorker-Skript hin- und hergeleitet werden, sind tiefe Klone eines Objekts.

1
Steve Griffith

Da diese Frage viel Aufmerksamkeit und Antworten in Bezug auf eingebaute Funktionen wie Object.assign oder benutzerdefinierten Code für Deep Clone bietet, möchte ich einige Bibliotheken für Deep Clone freigeben 

1. esclone

npm install --savedev esclone https://www.npmjs.com/package/esclone

Anwendungsbeispiel in ES6:

import esclone from "esclone";

const rockysGrandFather = {
  name: "Rockys grand father",
  father: "Don't know :("
};
const rockysFather = {
  name: "Rockys Father",
  father: rockysGrandFather
};

const rocky = {
  name: "Rocky",
  father: rockysFather
};

const rockyClone = esclone(rocky);

Anwendungsbeispiel in ES5:

var esclone = require("esclone")
var foo = new String("abcd")
var fooClone = esclone.default(foo)
console.log(fooClone)
console.log(foo === fooClone)

2. tiefe Kopie

npm install deep-copy https://www.npmjs.com/package/deep-copy

Beispiel:

var dcopy = require('deep-copy')

// deep copy object 
var copy = dcopy({a: {b: [{c: 5}]}})

// deep copy array 
var copy = dcopy([1, 2, {a: {b: 5}}])

3. klon-deep

$ npm install --save clone-deep https://www.npmjs.com/package/clone-deep

Beispiel:

var cloneDeep = require('clone-deep');

var obj = {a: 'b'};
var arr = [obj];

var copy = cloneDeep(arr);
obj.c = 'd';

console.log(copy);
//=> [{a: 'b'}] 

console.log(arr);
1
JTeam

Mein Szenario war ein bisschen anders. Ich hatte ein Objekt mit verschachtelten Objekten sowie Funktionen. Daher waren Object.assign() und JSON.stringify() keine Lösungen für mein Problem. Die Verwendung von Bibliotheken von Drittanbietern war für mich ebenfalls keine Option.

Aus diesem Grund habe ich beschlossen, eine einfache Funktion zu erstellen, um integrierte Methoden zum Kopieren eines Objekts mit seinen Literal-Eigenschaften, seinen verschachtelten Objekten und Funktionen zu verwenden.

let deepCopy = (target, source) => {
    Object.assign(target, source);
    // check if there's any nested objects
    Object.keys(source).forEach((prop) => {
        /**
          * assign function copies functions and
          * literals (int, strings, etc...)
          * except for objects and arrays, so:
          */
        if (typeof(source[prop]) === 'object') {
            // check if the item is, in fact, an array
            if (Array.isArray(source[prop])) {
                // clear the copied referenece of nested array
                target[prop] = Array();
                // iterate array's item and copy over
                source[prop].forEach((item, index) => {
                    // array's items could be objects too!
                    if (typeof(item) === 'object') {
                        // clear the copied referenece of nested objects
                        target[prop][index] = Object();
                        // and re do the process for nested objects
                        deepCopy(target[prop][index], item);
                    } else {
                        target[prop].Push(item);
                    }
                });
            // otherwise, treat it as an object
            } else {
                // clear the copied referenece of nested objects
                target[prop] = Object();
                // and re do the process for nested objects
                deepCopy(target[prop], source[prop]);
            }
        }
    });
};

Hier ist ein Testcode:

let a = {
    name: 'Human', 
    func: () => {
        console.log('Hi!');
    }, 
    prop: {
        age: 21, 
        info: {
            hasShirt: true, 
            hasHat: false
        }
    },
    mark: [89, 92, { exam: [1, 2, 3] }]
};

let b = Object();

deepCopy(b, a);

a.name = 'Alien';
a.func = () => { console.log('Wassup!'); };
a.prop.age = 1024;
a.prop.info.hasShirt = false;
a.mark[0] = 87;
a.mark[1] = 91;
a.mark[2].exam = [4, 5, 6];

console.log(a); // updated props
console.log(b);

Aus Gründen der Effizienz halte ich dies für die einfachste und effizienteste Lösung meines Problems. Ich würde mich über Kommentare zu diesem Algorithmus freuen, die ihn effizienter machen könnten.

1
Kamyar

Wenn Ihr Objekt verschachtelt ist und Datenobjekte, andere strukturierte Objekte oder Eigenschaftenobjekte usw. enthält, funktioniert die Verwendung von JSON.parse(JSON.stringify(object)) oder Object.assign({}, obj) oder $.extend(true, {}, obj) nicht. In diesem Fall benutzen Sie lodash. Es ist einfach und leicht.

var obj = {a: 25, b: {a: 1, b: 2}, c: new Date(), d: anotherNestedObject };
var A = _.cloneDeep(obj);

Nun wird A dein neuer geklonter obj ohne Referenzen sein. 

1
Prasanth Jaya

Hoffe das hilft.

function deepClone(obj) {
    /*
     * Duplicates an object 
     */

    var ret = null;
    if (obj !== Object(obj)) { // primitive types
        return obj;
    }
    if (obj instanceof String || obj instanceof Number || obj instanceof Boolean) { // string objecs
        ret = obj; // for ex: obj = new String("Spidergap")
    } else if (obj instanceof Date) { // date
        ret = new obj.constructor();
    } else
        ret = Object.create(obj.constructor.prototype);

    var prop = null;
    var allProps = Object.getOwnPropertyNames(obj); //gets non enumerables also


    var props = {};
    for (var i in allProps) {
        prop = allProps[i];
        props[prop] = false;
    }

    for (i in obj) {
        props[i] = i;
    }

    //now props contain both enums and non enums 
    var propDescriptor = null;
    var newPropVal = null; // value of the property in new object
    for (i in props) {
        prop = obj[i];
        propDescriptor = Object.getOwnPropertyDescriptor(obj, i);

        if (Array.isArray(prop)) { //not backward compatible
            prop = prop.slice(); // to copy the array
        } else
        if (prop instanceof Date == true) {
            prop = new prop.constructor();
        } else
        if (prop instanceof Object == true) {
            if (prop instanceof Function == true) { // function
                if (!Function.prototype.clone) {
                    Function.prototype.clone = function() {
                        var that = this;
                        var temp = function tmp() {
                            return that.apply(this, arguments);
                        };
                        for (var ky in this) {
                            temp[ky] = this[ky];
                        }
                        return temp;
                    }
                }
                prop = prop.clone();

            } else // normal object 
            {
                prop = deepClone(prop);
            }

        }

        newPropVal = {
            value: prop
        };
        if (propDescriptor) {
            /*
             * If property descriptors are there, they must be copied
             */
            newPropVal.enumerable = propDescriptor.enumerable;
            newPropVal.writable = propDescriptor.writable;

        }
        if (!ret.hasOwnProperty(i)) // when String or other predefined objects
            Object.defineProperty(ret, i, newPropVal); // non enumerable

    }
    return ret;
}

https://github.com/jinujd/Javascript-Deep-Clone

1

Wenn Sie es6 verwenden, können Sie dies einfach mit dem Spread-Operator tun.

let a = {id:1, name:'sample_name'}
let b = {...a};
1
Amaldev ps

Mit dem Spread-Operator können Sie das Objekt in JavaScript klonen.

// verbreite Operator, der den Concat-Job ausführt

let arr = [1,2,3];  let arr2 = [4,5];  arr = [...arr,...arr2]; console.log(arr); 
0
Raghul Shree

Dies ist meine Lösung, ohne eine Bibliothek oder native Javascript-Funktion zu verwenden.

function deepClone(obj) {
  if (typeof obj !== "object") {
    return obj;
  } else {
    let newObj =
      typeof obj === "object" && obj.length !== undefined ? [] : {};
    for (let key in obj) {
      if (key) {
        newObj[key] = deepClone(obj[key]);
      }
    }
    return newObj;
  }
}
0
Ankur Kedia

Wie wäre es, die schlüssel des Objekts mit seiner werte?

function deepClone(o) {
    var keys = Object.keys(o);
    var values = Object.values(o);

    var clone = {};

    keys.forEach(function(key, i) {
        clone[key] = typeof values[i] == 'object' ? Object.create(values[i]) : values[i];
    });

    return clone;
}

Hinweis: Diese Methode erstellt nicht notwendigerweise flache Kopien, sondern kopiert nur mit der Tiefe eines inneren Objekts. Wenn Sie also etwas wie {a: {b: {c: null}}} erhalten, werden nur die Objekte geklont sind direkt in ihnen, also ist deepClone(a.b).c technisch eine Referenz auf a.b.c, während deepClone(a).b ein Klon ist, keine Referenz.

0

Mit dem Vorschlag der neuen Methode Object.fromEntries () wird das auf neueren Versionen einiger Browser unterstützt ( reference ). Ich möchte mit dem nächsten rekursiven Ansatz beitragen:

const obj = {
  key1: {key11: "key11", key12: "key12", key13: {key131: 22}},
  key2: {key21: "key21", key22: "key22"},
  key3: "key3",
  key4: [1,2,3, {key: "value"}]
}

const cloneObj = (obj) =>
{
    if (Object(obj) !== obj)
       return obj;
    else if (Array.isArray(obj))
       return obj.map(cloneObj);

    return Object.fromEntries(Object.entries(obj).map(
        ([k,v]) => ([k, cloneObj(v)])
    ));
}

// Clone the original object.
let newObj = cloneObj(obj);

// Make changes on the original object.
obj.key1.key11 = "TEST";
obj.key3 = "TEST";
obj.key1.key13.key131 = "TEST";
obj.key4[1] = "TEST";
obj.key4[3].key = "TEST";

// Display both objects on the console.
console.log("Original object: ", obj);
console.log("Cloned object: ", newObj);
.as-console {background-color:black !important; color:Lime;}
.as-console-wrapper {max-height:100% !important; top:0;}
0
Shidersz
function clone(obj) {
    var copy;

    // Handle the 3 simple types, and null or undefined
    if (null == obj || "object" != typeof obj) return obj;

    // Handle Date
    if (obj instanceof Date) {
        copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }

    // Handle Array
    if (obj instanceof Array) {
        copy = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            copy[i] = clone(obj[i]);
        }
        return copy;
    }

    // Handle Object
    if (obj instanceof Object) {
        copy = {};
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]);
        }
        return copy;
    }

    throw new Error("Unable to copy obj! Its type isn't supported.");
}

verwenden Sie die folgende Methode anstelle von JSON.parse(JSON.stringify(obj)), da langsamer ist als die folgende Methode 

Wie kopiere ich ein JavaScript-Objekt richtig?

0
shakthi nagaraj