Вам определенно нужен deepClone
Можно взять готовый например из lodash, но я бы предложил Вам свою реализацию.
Пока писал ее в ответ, понял, что в очередной раз мой ответ превращается в целую статью, поэтому разместил ее на хабре:
https://habr.com/ru/post/466535/
Ну или можете просто скопировать код и использовать:
function deepClone(source) {
return ({
'object': cloneObject,
'function': cloneFunction
}[typeof source] || clonePrimitive)(source)();
}
function cloneObject(source) {
return (Array.isArray(source)
? () => source.map(deepClone)
: clonePrototype(source, cloneFields(source, simpleFunctor({})))
);
}
function cloneFunction(source) {
return cloneFields(source, simpleFunctor(function() {
return source.apply(this, arguments);
}));
}
function clonePrimitive(source) {
return () => source;
}
function simpleFunctor(value) {
return mapper => mapper ? simpleFunctor(mapper(value)) : value;
}
function makeCloneFieldReducer(source) {
return (destinationFunctor, field) => {
const descriptor = Object.getOwnPropertyDescriptor(source, field);
return destinationFunctor(destination => Object.defineProperty(destination, field, 'value' in descriptor ? {
...descriptor,
value: deepClone(descriptor.value)
} : descriptor));
};
}
function cloneFields(source, destinationFunctor) {
return (Object.getOwnPropertyNames(source)
.concat(Object.getOwnPropertySymbols(source))
.reduce(makeCloneFieldReducer(source), destinationFunctor)
);
}
function clonePrototype(source, destinationFunctor) {
return destinationFunctor(destination => Object.setPrototypeOf(destination, Object.getPrototypeOf(source)));
}