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.

169voto

Eugene Tiurin Punkte 3709

Der effiziente Weg, ein Objekt in einer Zeile Code zu klonen (nicht tief zu klonen)

Eine Object.assign Methode ist Teil des ECMAScript 2015 (ES6)-Standards und tut genau das, was Sie brauchen.

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

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

Lesen Sie mehr...

El Polyfill um ältere Browser zu unterstützen:

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;
    }
  });
}

135voto

tim-montague Punkte 13518

Deep Copy nach Leistung: Rangfolge vom Besten zum Schlechtesten

  • Spread-Operator ... (nur primitive Arrays)
  • splice(0) (nur primitive Arrays)
  • slice() (nur primitive Arrays)
  • concat() (nur primitive Arrays)
  • benutzerdefinierte Funktion, wie unten dargestellt (beliebiges Array)
  • jQuery's $.extend() (beliebiges Array)
  • JSON.parse(JSON.stringify()) (nur primitive und literale Arrays)
  • Underscores _.clone() (nur primitive und literale Arrays)
  • Lodash's _.cloneDeep() (beliebiges Array)

Wo:

  • Primitive = Zeichenketten, Zahlen und Boolesche Werte
  • Literale = Objektliterale {} , Array-Literale []
  • any = Primitive, Literale und Prototypen

Tiefes Kopieren eines Arrays von Primitiven:

let arr1a = [1, 'a', true];

Um Arrays nur mit Primitiven (d.h. Zahlen, Strings und Booleans) tief zu kopieren, ist eine Neuzuweisung erforderlich, slice() , concat() und Underscore's clone() verwendet werden können.

Bei der Spreizung ist die Leistung am höchsten:

let arr1b = [...arr1a];

Und wo slice() hat eine bessere Leistung als concat() : https://jsbench.me/x5ktn7o94d/

let arr1c = arr1a.splice(0);
let arr1d = arr1a.slice();
let arr1e = arr1a.concat();

Tiefes Kopieren eines Arrays von Primitiv- und Objektliteralen:

let arr2a = [1, 'a', true, {}, []];
let arr2b = JSON.parse(JSON.stringify(arr2a));

Tiefes Kopieren einer Reihe von Primitiven, Objektliteralen und Prototypen:

let arr3a = [1, 'a', true, {}, [], new Object()];

Schreiben Sie eine benutzerdefinierte Funktion (mit höherer Leistung als $.extend() o JSON.parse ) :

function copy(aObject) {
  // Prevent undefined objects
  // if (!aObject) return aObject;

  let bObject = Array.isArray(aObject) ? [] : {};

  let value;
  for (const key in aObject) {

    // Prevent self-references to parent object
    // if (Object.is(aObject[key], aObject)) continue;

    value = aObject[key];

    bObject[key] = (typeof value === "object") ? copy(value) : value;
  }

  return bObject;
}

let arr3b = copy(arr3a);

Oder verwenden Sie Hilfsfunktionen von Drittanbietern:

let arr3c = $.extend(true, [], arr3a); // jQuery Extend
let arr3d = _.cloneDeep(arr3a); // Lodash

Hinweis: jQuery's $.extend hat auch eine bessere Leistung als JSON.parse(JSON.stringify()) :

122voto

Alan Punkte 241

Ich verwende das hier:

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;
}

115voto

Kamarey Punkte 10466

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;
}

Test:

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);

103voto

Tính Ngô Quang Punkte 3750

Tiefes Kopieren von Objekten in JavaScript (meiner Meinung nach die beste und einfachste Methode)

1. Verwendung von JSON.parse(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. erstellte Methode verwenden

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. Verwendung von Lo-Dashs _.cloneDeep enlace 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. Verwendung der Methode Object.assign()

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. die Verwendung von Underscore.js _.clone enlace 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.)

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

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