5167 Stimmen

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

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

Ich habe Dinge getan wie obj = JSON.parse(JSON.stringify(o)); stellen aber die Effizienz in Frage.

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

566 Stimmen

Eval ist nicht böse. Schlechtes Benutzen von Eval schon. Wenn Sie Angst vor seinen Nebenwirkungen haben, verwenden Sie es falsch. Die Nebenwirkungen, die Sie fürchten, sind der Grund, warum Sie es verwenden. Hat eigentlich irgendjemand Ihre Frage beantwortet?

15 Stimmen

Das Klonen von Objekten ist eine knifflige Angelegenheit, insbesondere bei benutzerdefinierten Objekten beliebiger Sammlungen. Wahrscheinlich gibt es deshalb keine fertige Methode, dies zu tun.

12 Stimmen

eval() ist im Allgemeinen eine schlechte Idee, weil viele Javascript-Engine-Optimierer abschalten müssen, wenn sie mit Variablen arbeiten, die über eval . Nur mit eval() in Ihrem Code kann zu einer schlechteren Leistung führen.

48voto

Matt Browne Punkte 11583

Hier ist eine Version der obigen Antwort von ConroyP, die auch funktioniert, wenn der Konstruktor erforderliche 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 meinem simpleoo Bibliothek.

編集する。

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

/**
 * 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();
    };
}

33voto

nathan rogers Punkte 197

Im Folgenden werden zwei Instanzen desselben Objekts erstellt. Ich habe es gefunden und verwende es gerade. Es ist einfach und leicht zu benutzen.

var objToCreate = JSON.parse(JSON.stringify(cloneThis));

31voto

Chris Broski Punkte 2242

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 kurz und bündig, funktioniert wie erwartet und man braucht keine Bibliothek.


EDITAR:

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

var newObject = Object.create(oldObject);

HINWEIS: Wenn Sie etwas davon verwenden, können Sie Probleme mit einigen Iterationen haben, die hasOwnProperty . Weil, create ein neues leeres Objekt erstellen, das von oldObject . Aber es ist immer noch nützlich und praktisch für das Klonen von Objekten.

Zum Beispiel, wenn oldObject.a = 5;

newObject.a; // is 5

sondern:

oldObject.hasOwnProperty(a); // is true
newObject.hasOwnProperty(a); // is false

25voto

Mark Cidade Punkte 95914
function clone(obj)
 { var clone = {};
   clone.prototype = obj.prototype;
   for (property in obj) clone[property] = obj[property];
   return clone;
 }

23voto

opensas Punkte 56212

Lodash hat eine schöne _.cloneDeep(Wert) Methode:

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

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X