Comments 37
let originalObject = {a: 1, b: 2, c: {d: 3, e: 4}};
let clonedObject = JSON.parse(JSON.stringify(originalObject));
clonedObject.c.d = 7;
console.dir(originalObject); // {"a":1,"b":2,"c":{"d":3,"e":4}}
console.dir(clonedObject); // {"a":1,"b":2,"c":{"d":7,"e":4}}
И зачем огород городить? :)
Другая тема — копирование методов…
Поиск в Гугле.
P.S. Если искать по сути, а не по названию функции, то результатов может оказаться немного больше.
const obj = { ... }
const clObj = JSON.parse(JSON.stringify(obj))
JSON.parse
, огромное спасибо ему за это. Как оказалась JSON.parse
уступает в производительности в 10 раз. Ссылка натестJSON не может содержать функции. А значит, склонировать без потерь получится не любой объект...
не встречал ничего лучшеНавскидку:
JSON.parse(JSON.stringify(undefined));
let d = new Date();
JSON.parse(JSON.stringify(d));
let child = {}, parent = {};
child.parent = parent; parent.child = child;
JSON.parse(JSON.stringify(child));
Для простых случаев вполне подойдет. Однако мы модем клонировать и пользщовательские объекты модем клонировать их вместе с методами, восстанавливать конструктор и соответственно прототип объекта
Как бы сказать помягче?
На выходе из вашей функции получается совсем не то, что должно быть.
Z object after cloning: { a: [ 1, 2, 3 ] }
Y object: { a: { '0': 1, '1': 2, '2': 3 }, addnlProp: { fd: 45 } }
function deepClone(obj) {
const test1 = { a: { d: [1, 2, 3]}, b: 5 };
const test2 = deepClone(test1);
test2.a.d.push('arr')
test2.b = 9;
console.log('test1 object: ', test1);
console.log('test2 object: ', test2);
function deepClone(obj) {
const clObj = {};
for(const i in obj) {
if (obj[i] instanceof Object && !(obj[i] instanceof Array)) {
clObj[i] = deepClone(obj[i]);
continue;
}
clObj[i] = obj[i];
}
return clObj;
}
Добавив одно условие, я скопировал массив верно, но при этом он остался зависимым от массива из другого объекта. Хотя подобное следовало ожидать, но все же интересная особенность
![image](https://habrastorage.org/webt/ld/eu/rg/ldeurgpemslu41fjkygy5yo0yvw.jpeg)
Все таки добью эту функцию, чтобы работала корректно не только с объектами, а как минимум еще с массивом. После чего внесу правки в статью. Еще раз, спасибо вам за отзыва )
По хорошему, Вам нужен вызов `obj[i].map(deepClone)`, в массиве могут быть не только скаляры.
Отличная идея с map, нужно попробовать ваш вариант на практике и посмотреть на результат, спасибо )
Ещё один совет: когда наиграетесь с этим велосипедом, поищите удовлетворяющую Вас open source альтернативу и используйте её — ни к чему тратить силы на самостоятельную поддержку подобных функций.
На примере deepClone: рано или поздно Вы столкнётесь с циклическими ссылками и начнёте решать эту проблему. Есть несколько способов её решения, Вам придётся выбирать. Потом будут новые проблемы, возможно захочется сохранить прототипы… Путь даже такой элементарной штучки довольно долог. Но в существующих реализациях зачастую весь этот путь уже пройден. И для решения вновь возникающих проблем у Вас есть огромный штат добровольцев(включая Вас).
В общем, если проблема не академическая или «на поиграться», всегда стоит начинать с поиска существующих решений. Жизнь одна, если каждый будет распыляться на подобные мелочи. ни у кого не хватит времени создать что-то стоящее.
Хм, растёкся я тут мыслью по древу. извините.
Думаю, в комментариях есть место ещё и для такой ссылочки: Deep-copying in JavaScript
Я бы еще рассмотрел кейс клонирования объектов с сохранением их прототипов: объекты могут содержать методы, которые мы хотим иметь и у клонов.
Каждый js-программист наверняка без труда ответит на этот вопрос, но все же скажем: примитивные типы данных передаются в функцию всегда только по значению, а ссылочные всегда только по ссылке.
Я не отношусь к категории "каждый программист" потому что думаю что в JS все параметры передаются в функцию по значению. Просто для объектов в качестве значения выступает ссылка на объект. Вы внутри функции можете поменять поля в этом объекте. Но не сможете присвоить параметру новое значение.
Второй момент про алгоритм клонирования. Вцелом направление правильное, на как минимум нужно учес еще и клонирование Array. Хотя если по-хорошему то нужно еще как-то работать с прототипами а также и с другими типами JS
То есть если у Вас объект Dog то его кот также должен быть объектом типа Dog
Способ один — значение. В качестве значения используется ссылка. Тем кто не программировал на более древних языках (Пскаль, Си, PL/1) это разница не совсем ясна
Еси переменная передается по ссылке то ее значение меняется если его изменить внутри функции. В JS Вы можете изменить сам объект и это будет видно извне.
Но если вы сделаете так
var obj0 = {}
function(obj1) {
obj1 = {}
return obj1
}
obj0 !== obj1 // true
Если бы объект передалася по ссылке то
obj0 === obj1 // true
Просто по ссылке они передаются неявным образом.
Передача переменной по ссылке на примере php: 3v4l.org/TQXg1
В javascript ничего подобного нет, если вы что-то присваиваете переменной, старое значение теряется.
Просто для объектов передаётся значение указателя на тот же объект, что позволяет мутировать этот объект, но не позволяет изменить саму переменную.
_.deepClone() ?
let num = 10;
let obj = { a: 5, b: 6 };
Как видим, в первом случае мы перезаписали значение переменной, а во втором расширили объект.Точно расширили?
function insertValToArr(arr, val) {
const newArr = [];
arr.forEach((value, ind) => { newArr[ind] = value});
newArr.push(val);
return newArr;
}
forEach здесь не нужен, лучше использовать map:
function insertValToArr(arr, val) {
const newArr = arr.map((value) => value);
newArr.push(val);
return newArr;
}
А ещё лучше сократить до однострочника:
const insertValToArr = (arr, val) => arr.map((value) => value).concat(val);
И в JS есть 7 примитивных типов данных и всего один ссылочный — Object (MDN). Array, Function, Maps, Sets и т. д. — это всё реализации объекта.
insertValToArr
. От себя могу добавить, что можно подобное сделать и через spread, но данный вариант скорее подойдет для одномерных массивов.function insertValToArr(arr, val) {
return [...arr, val];
}
Мы всегда можем создать объект без прототипа через Object.create. Так как у такого объекта не будет прототипа Object, то и логично, что instanceof не найдет его там.
const a = Object.create(null);
console.log(a instanceof Object) // false
const b = {};
console.log(b instanceof Object) // true
Независимое глубокое клонирование объектов в JavaScript