Кой е най-ефективният начин за клониране на обект в JavaScript? Виждал съм, че се използва obj = eval(uneval(o));
, но това е нестандартно и се поддържа само от Firefox.
Правил съм неща като obj = JSON.parse(JSON.stringify(o));
, но се съмнявам в ефективността.
Виждал съм и рекурсивни функции за копиране с различни недостатъци.
Изненадан съм, че не съществува канонично решение.
Нарича се "структурирано клониране", работи експериментално в Node 11 и по-нови версии и се надяваме, че ще се появи в браузърите. Вижте този отговор за повече подробности.
Ако не използвате Date
s, функции, undefined
, Infinity
, RegExps, Maps, Sets, Blobs, FileLists, ImageDatas, sparse Arrays, Typed Arrays или други сложни типове във вашия обект, много прост one liner за дълбоко клониране на обект е:
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()
Вижте отговора на Corban's за еталони.
Тъй като клонирането на обекти не е тривиално (сложни типове, кръгови препратки, функции и т.н.), повечето големи библиотеки предоставят функция за клониране на обекти. Не изобретявайте колелото - ако вече използвате някоя библиотека, проверете дали тя има функция за клониране на обекти. Например,
cloneDeep
; може да се импортира отделно чрез модула lodash.clonedeep и вероятно е най-добрият избор, ако все още не използвате библиотека, която предоставя функция за дълбоко клониранеangular.copy
jQuery.extend(true, { }, oldObject)
; .clone()
клонира само DOM елементиЗа пълнота отбележете, че ES6 предлага два механизма за повърхностно копиране: Object.assign()
и spread operator.
Ако няма вграден такъв, можете да опитате:
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;
}
function clone(obj)
{ var clone = {};
clone.prototype = obj.prototype;
for (property in obj) clone[property] = obj[property];
return clone;
}