Mi a leghatékonyabb módja egy objektum mélyklónozásának JavaScriptben?

Mi a leghatékonyabb módja egy JavaScript objektum klónozásának? Láttam, hogy az obj = eval(uneval(o));-t használják, de ez nem szabványos, és csak a Firefox támogatja.

I've done things like obj = JSON.parse(JSON.stringify(o));, de megkérdőjelezem a hatékonyságot. <br/br/><br/br/> Láttam rekurzív másoló függvényeket is különböző hibákkal. <br/br /> I'm meglepő, hogy nincs kanonikus megoldás.

Megoldás

Natív mély klónozás

Ezt "strukturált klónozásnak" hívják, kísérletképpen működik a Node 11-ben és később, és remélhetőleg a böngészőkben is landol. További részletekért lásd ez a válasz.

Gyors klónozás adatvesztéssel - JSON.parse/stringify

Ha nem használsz Dates, függvényeket, undefined, Infinity, RegExps, Maps, Sets, Blobs, FileLists, ImageDatas, sparse Arrays, Typed Arrays vagy más összetett típusokat az objektumodon belül, egy nagyon egyszerű egysoros egy objektum mélyklónozásához:

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

Lásd Corban's answer a benchmarkokat.

Megbízható klónozás könyvtár használatával

Mivel az objektumok klónozása nem triviális (összetett típusok, körkörös hivatkozások, függvények stb.), a legtöbb nagy könyvtár biztosít funkciót az objektumok klónozására. Ne találd fel újra a kereket - ha már használsz egy könyvtárat, ellenőrizd, hogy van-e benne objektumklónozó funkció. Például,

ES6

A teljesség kedvéért jegyezzük meg, hogy az ES6 két sekély másolási mechanizmust kínál: Object.assign() és a spread operator.

Kommentárok (24)

Ha nem lenne beépített, megpróbálhatná:

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;
}
Kommentárok (11)
function clone(obj)
 { var clone = {};
   clone.prototype = obj.prototype;
   for (property in obj) clone[property] = obj[property];
   return clone;
 }
Kommentárok (5)