Koks yra veiksmingiausias būdas "JavaScript" giliai klonuoti objektą?

Koks veiksmingiausias būdas klonuoti "JavaScript" objektą? Esu matęs, kad naudojamas obj = eval(uneval(o));, bet tai nestandartinis variantas, kurį palaiko tik "Firefox".


Esu daręs tokius dalykus kaip obj = JSON.parse(JSON.stringify(o));, bet abejoju dėl efektyvumo.

Taip pat esu matęs rekursinio kopijavimo funkcijų su įvairiais trūkumais.
Aš'stebiuosi, kad nėra kanoninio sprendimo.

Sprendimas

Gimtasis gilusis klonavimas

Tai vadinama "struktūrizuotu klonavimu", eksperimentiniu būdu veikia "Node 11" ir vėlesnėse versijose ir, tikiuosi, bus įdiegta naršyklėse. Daugiau informacijos žr. šis atsakymas.

Greitas klonavimas prarandant duomenis - JSON.parse/stringify

Jei objekte nenaudojate Date, funkcijų, undefined, Infinity, RegExps, Maps, Sets, Blobs, FileLists, ImageData, retų masyvų, tipinių masyvų ar kitų sudėtingų tipų, labai paprasta viena eilutė giliam objekto klonavimui yra:

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

Žr. Corban's answer, kur pateikiami lyginamieji pavyzdžiai.

Patikimas klonavimas naudojant biblioteką

Kadangi objektų klonavimas nėra trivialus (sudėtingi tipai, žiedinės nuorodos, funkcijos ir t. t.), dauguma pagrindinių bibliotekų pateikia objektų klonavimo funkciją. Neišradinėkite dviračio - jei jau naudojate biblioteką, patikrinkite, ar ji turi objektų klonavimo funkciją. Pvz,

ES6

Išsamumo dėlei atkreipkite dėmesį, kad ES6 siūlo du negilaus kopijavimo mechanizmus: Object.assign() ir spread operator.

Komentarai (24)

Jei nėra jokio integruoto, galite pabandyti:

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