Wenn Sie nur einfache Objekte klonen müssen, einfach
tun
JSON.parse (JSON.stringify (obj))
würde ausreichen.
Aber das funktioniert offensichtlich nicht in allen Fällen, da JSON.stringify
nicht mit zirkulären Referenzen umgehen und Funktionen auslöscht.
Wenn Sie also darüber hinaus gehen wollen, werden die Dinge komplizierter und Sie müssen entweder auf eine Utility-Bibliothek zurückgreifen oder müssen Ihre eigene Deep Clone-Methode implementieren.
Hier ist eine Beispielimplementierung, die ein Niveau der Tiefe zu klonen erwartet.
(function (Object, Array) {
function cloneObject(deep, scope, clonedScope) {
var type = typeof this,
clone = {},
isCR = -1;
deep = Number(deep) || 0;
scope = scope || [];
clonedScope = clonedScope || [];
if (!Array.isArray(scope) || !Array.isArray(clonedScope) || clonedScope.length !== scope.length) {
throw new TypeError("Unexpected input");
}
//If we find a primitive, we reeturn its value.
if (type !== "object") {
return this.valueOf();
}
scope.push(this);
clonedScope.push(clone);
if (0 === deep) { //If we reached the recursion limit, we can perform a shallow copy
for (var prop in this) {
clone[prop] = this[prop];
}
} else { //Otherwise we need to make some checks first.
for (var prop in this) {
if ((isCR = scope.indexOf(this[prop])) > -1) { //If we find a circular reference, we want create a new circular reference to the cloned version.
clone[prop] = clonedScope[isCR];
} else if (typeof this[prop] !== "undefined" && this[prop] !== null) { //Otherwise continue cloning.
clone[prop] = (typeof this[prop] !== "object" ? this[prop] : this[prop].clone(deep - 1, scope, clonedScope)); //If we find a non object, we can directly assign it. Otherwise we need to recursively call the clone function, counting down the limit, and injecting the scopeArrays, to find circular references.
} else { //If the property is undefined or null, assign it as such.
clone[prop] = this[prop];
}
}
}
scope.pop(); //If we leave a recursion leve, we remove the current object from the list.
clonedScope.pop();
return clone;
}
function cloneArray(deep, scope, clonedScope) {
var clone = [];
deep = Number(deep) || 0;
scope = scope || [];
clonedScope = clonedScope || [];
if (!Array.isArray(scope) || !Array.isArray(clonedScope) || clonedScope.length !== scope.length) {
throw new TypeError("Unexpected input");
}
scope.push(this);
clonedScope.push(this);
if (0 === deep) clone = this.concat();
else this.forEach(function (e) {
if ((isCR = scope.indexOf(e)) > -1) {
clone.push(clonedScope[isCR]);
} else if (typeof e !== "undefined" && e !== null) {
clone.push((typeof e !== "object" ? e : e.clone(deep - 1, scope, clonedScope)));
} else {
clone.push(e);
}
});
scope.pop();
clonedScope.pop();
return clone;
}
Object.defineProperty(Object.prototype, "clone", {
enumerable: false,
value: cloneObject
});
Object.defineProperty(Array.prototype, "clone", {
enumerable: false,
value: cloneArray
});
})(Object, Array);
Beachten Sie, dass die die Einbauten Prototypen erstreckt, ist oft verpönt, jedoch habe ich beschlossen, es so zu tun, um eine zusätzliche typecheck zu vermeiden und die Logik für Arrays aufgeteilt und Objekte ein bisschen mehr. Dies kann leicht zu einer normalen Funktion refaktoriert werden
Einige Tests, um zu überprüfen, ob wir tatsächlich neue Referenzen haben.
var first = {
a: {
b: "b",
c: {
}
},
b: "asd",
c: [{}],
d: undefined,
e: null,
f: function a() {} //functions keep their original reference..
};
first.a.c.a = first.a; //Circular object reference
first.c.push(first.c); //Circular array reference
var second = first.clone(Infinity);
console.log(second, second.a === second.a.c.a, first.a !== second.a.c.a); //..., true, true.
Es kann eine Menge Platz für Verbesserungen, ich particularily mag nicht, wie der Umfang und clonedScope gets injiziert. Wenn jemand eine bessere Idee hat, kreisförmige Referenzen zu finden und wieder anzubringen, würde ich mich freuen, die Antwort zu aktualisieren
Hier ist ein Fiddle auch.
"Ohne Referenz zuweisen" heißt in JavaScript und ähnlichen Sprachen "Klon". Siehe [diese Frage] (http://stackoverflow.com/questions/122102/what-ist-most-efficient-way-to-clone-an- object) für mögliche Implementierungen. – georg
@georg: Danke. Klon ist das richtige Wort. Ich habe es verpasst – SharpCoder
@ georg-die akzeptierte Antwort gibt es keine besonders gute Antwort, es sagt im Wesentlichen "jQuery verwenden". – RobG