Antworten:
Bei Dienstprogrammen und Klassen, bei denen nicht jeder Leistungsabfall beeinträchtigt werden muss, betrüge ich häufig und verwende JSON, um eine tiefe Kopie zu erstellen:
function clone(a) {
return JSON.parse(JSON.stringify(a));
}
Dies ist nicht die einzige oder eleganteste Antwort. Alle anderen Antworten sollten bei Produktionsengpässen berücksichtigt werden. Dies ist jedoch eine schnelle und schmutzige Lösung, sehr effektiv und in den meisten Situationen nützlich, in denen ich einen einfachen Hash von Eigenschaften klonen würde.
newObj = obj.clone(args...);
Object.assign wurde in keiner der obigen Antworten erwähnt.
let cloned = Object.assign({}, source);
Wenn Sie mit ES6 arbeiten, können Sie den Spread-Operator verwenden:
let cloned = { ... source };
Referenz: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
let a = {x:1}; let b = Object.assign({}, a); a.x = 2; a.y = 1; console.log(a, b);
Es gibt einige Node-Module, wenn Sie nicht "Ihre eigenen rollen" möchten. Dieser sieht gut aus: https://www.npmjs.com/package/clone
Sieht so aus, als würde es alle möglichen Dinge behandeln, einschließlich Zirkelverweise. Von der Github- Seite:
Klonmeister klonen Objekte, Arrays, Datumsobjekte und RegEx-Objekte. Alles wird rekursiv geklont, sodass Sie beispielsweise Datumsangaben in Arrays in Objekten klonen können. [...] Rundschreiben? Ja!
Es ist schwierig, eine generische, aber nützliche Klonoperation durchzuführen, da es davon abhängt, wie das bestimmte Objekt funktionieren soll, was rekursiv geklont und was nur kopiert werden soll.
Etwas, das nützlich sein kann, ist
function clone(x)
{
if (x === null || x === undefined)
return x;
if (typeof x.clone === "function")
return x.clone();
if (x.constructor == Array)
{
var r = [];
for (var i=0,n=x.length; i<n; i++)
r.push(clone(x[i]));
return r;
}
return x;
}
In diesem Code ist die Logik
null
oder undefined
einfach nur zurückgeben (der Sonderfall wird benötigt, weil es ein Fehler ist, zu versuchen, festzustellen, ob eine clone
Methode vorhanden ist)clone
Methode? dann benutze dasDiese Klonfunktion sollte es ermöglichen, benutzerdefinierte Klonmethoden einfach zu implementieren ... zum Beispiel
function Point(x, y)
{
this.x = x;
this.y = y;
...
}
Point.prototype.clone = function()
{
return new Point(this.x, this.y);
};
function Polygon(points, style)
{
this.points = points;
this.style = style;
...
}
Polygon.prototype.clone = function()
{
return new Polygon(clone(this.points),
this.style);
};
Wenn Sie im Objekt wissen, dass ein korrekter Klonvorgang für ein bestimmtes Array nur eine flache Kopie ist, können Sie values.slice()
stattdessen aufrufen clone(values)
.
Zum Beispiel fordere ich im obigen Code ausdrücklich, dass beim Klonen eines Polygonobjekts die Punkte geklont werden, aber dasselbe Stilobjekt verwendet wird. Wenn ich stattdessen auch das Stilobjekt klonen möchte, kann ich einfach übergeben clone(this.style)
.
.clone
Methode selbst implementieren müssen. Dies ist der beste Weg, um mit dem Klonen von Objekten umzugehen.
if (x.clone)
sollte seinif (typeof x.clone === 'function')
Es gibt keine native Methode zum Klonen von Objekten. Unterstrichen implementiert, _.clone
was ein flacher Klon ist.
_.clone = function(obj) {
return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
};
Es schneidet es entweder oder erweitert es.
Hier ist _.extend
// extend the obj (first parameter)
_.extend = function(obj) {
// for each other parameter
each(slice.call(arguments, 1), function(source) {
// loop through all properties of the other objects
for (var prop in source) {
// if the property is not undefined then add it to the object.
if (source[prop] !== void 0) obj[prop] = source[prop];
}
});
// return the object (first parameter)
return obj;
};
Extend durchläuft einfach alle Elemente und erstellt ein neues Objekt mit den darin enthaltenen Elementen.
Sie können Ihre eigene naive Implementierung einführen, wenn Sie möchten
function clone(o) {
var ret = {};
Object.keys(o).forEach(function (val) {
ret[val] = o[val];
});
return ret;
}
Es gibt gute Gründe, tiefes Klonen zu vermeiden, da Verschlüsse nicht geklont werden können.
Ich habe persönlich eine Frage gestellt deep cloning objects before
und bin zu dem Schluss gekommen, dass Sie es einfach nicht tun.
Meine Empfehlung ist die Verwendung underscore
und die _.clone
Methode für flache Klone
Für eine flache Kopie verwende ich gerne das Verkleinerungsmuster (normalerweise in einem Modul oder ähnlichem) wie folgt:
var newObject = Object.keys(original).reduce(function (obj, item) {
obj[item] = original[item];
return obj;
},{});
Hier ist ein jsperf für einige der Optionen: http://jsperf.com/shallow-copying
Alte Frage, aber es gibt eine elegantere Antwort als bisher vorgeschlagen; Verwenden Sie die integrierten utils._extend:
var extend = require("util")._extend;
var varToCopy = { test: 12345, nested: { val: 6789 } };
var copiedObject = extend({}, varToCopy);
console.log(copiedObject);
// outputs:
// { test: 12345, nested: { val: 6789 } }
Beachten Sie die Verwendung des ersten Parameters mit einem leeren Objekt {} - dies weist darauf hin, dass die kopierten Objekte in ein neues Objekt kopiert werden müssen. Wenn Sie ein vorhandenes Objekt als ersten Parameter verwenden, werden die zweiten (und alle nachfolgenden) Parameter über die erste Parametervariable tief zusammengeführt.
Mit den obigen Beispielvariablen können Sie auch Folgendes tun:
var anotherMergeVar = { foo: "bar" };
extend(copiedObject, { anotherParam: 'value' }, anotherMergeVar);
console.log(copiedObject);
// outputs:
// { test: 12345, nested: { val: 6789 }, anotherParam: 'value', foo: 'bar' }
Sehr praktisches Dienstprogramm, insbesondere dort, wo ich es gewohnt bin, in AngularJS und jQuery zu erweitern.
Hoffe das hilft jemand anderem; Überschreiben von Objektreferenzen sind ein Elend, und dies löst es jedes Mal!
Je nachdem, was Sie mit Ihrem geklonten Objekt tun möchten, können Sie den prototypischen Vererbungsmechanismus von Javascript verwenden und ein etwas geklontes Objekt erzielen durch:
var clonedObject = Object.create(originalObject);
Denken Sie daran, dass dies kein vollständiger Klon ist - zum Guten oder Schlechten.
Eine gute Sache dabei ist, dass Sie das Objekt tatsächlich nicht dupliziert haben, sodass der Speicherbedarf gering ist.
Einige schwierige Dinge, die Sie bei dieser Methode beachten sollten, sind, dass die Iteration der in der Prototypenkette definierten Eigenschaften manchmal etwas anders funktioniert und dass Änderungen am ursprünglichen Objekt auch das geklonte Objekt betreffen, sofern diese Eigenschaft nicht auch für sich selbst festgelegt wurde .
var a = {foo: "bar"}, b = Object.create(a); a.foo = "broken"; console.log(b.foo); // "broken";
b.foo = "working"; console.log(a.foo); // still "broken";
Man muss sich natürlich bewusst sein, dass Änderungen am Originalobjekt im "Klon" wiedergegeben werden und dass Änderungen am "Klon" nicht im Originalobjekt wiedergegeben werden - aber ich würde es nicht als gefährlich bezeichnen - Es hängt alles davon ab, was Sie mit Ihrem Klon machen wollen
Ich habe eine vollständige, tiefe Kopie implementiert. Ich glaube, es ist die beste Wahl für eine generische Klonmethode, aber es werden keine zyklischen Referenzen verarbeitet.
parent = {'prop_chain':3}
obj = Object.create(parent)
obj.a=0; obj.b=1; obj.c=2;
obj2 = copy(obj)
console.log(obj, obj.prop_chain)
// '{'a':0, 'b':1, 'c':2} 3
console.log(obj2, obj2.prop_chain)
// '{'a':0, 'b':1, 'c':2} 3
parent.prop_chain=4
obj2.a = 15
console.log(obj, obj.prop_chain)
// '{'a':0, 'b':1, 'c':2} 4
console.log(obj2, obj2.prop_chain)
// '{'a':15, 'b':1, 'c':2} 4
Dieser Code kopiert Objekte mit ihren Prototypen und kopiert auch Funktionen (kann für jemanden nützlich sein).
function copy(obj) {
// (F.prototype will hold the object prototype chain)
function F() {}
var newObj;
if(typeof obj.clone === 'function')
return obj.clone()
// To copy something that is not an object, just return it:
if(typeof obj !== 'object' && typeof obj !== 'function' || obj == null)
return obj;
if(typeof obj === 'object') {
// Copy the prototype:
newObj = {}
var proto = Object.getPrototypeOf(obj)
Object.setPrototypeOf(newObj, proto)
} else {
// If the object is a function the function evaluate it:
var aux
newObj = eval('aux='+obj.toString())
// And copy the prototype:
newObj.prototype = obj.prototype
}
// Copy the object normal properties with a deep copy:
for(var i in obj) {
if(obj.hasOwnProperty(i)) {
if(typeof obj[i] !== 'object')
newObj[i] = obj[i]
else
newObj[i] = copy(obj[i])
}
}
return newObj;
}
Mit dieser Kopie kann ich keinen Unterschied zwischen dem Original und dem kopierten finden, außer wenn das Original Verschlüsse für seine Konstruktion verwendet hat, daher denke ich, dass es eine gute Implementierung ist.
Ich hoffe, es hilft
Objekte und Arrays in JavaScript verwenden den Aufruf als Referenz. Wenn Sie den kopierten Wert aktualisieren, wird dies möglicherweise auf das ursprüngliche Objekt angewendet. Um dies zu verhindern, können Sie das Objekt mit dem Befehl run der Methode cloneDeep der lodash-Bibliothek tief klonen und verhindern, dass die Referenz übergeben wird
npm install lodash
const ld = require('lodash')
const objectToCopy = {name: "john", age: 24}
const clonedObject = ld.cloneDeep(objectToCopy)