Поиск в Google для «javascript clone object» приносит действительно странные результаты, некоторые из них безнадежно устарели, а некоторые слишком сложны, не так ли просто, как просто:
let clone = {...original};
Что-то не так с этим?
Поиск в Google для «javascript clone object» приносит действительно странные результаты, некоторые из них безнадежно устарели, а некоторые слишком сложны, не так ли просто, как просто:
let clone = {...original};
Что-то не так с этим?
Ответы:
Это хорошо для мелкого клонирования . Распространение объекта является стандартной частью ECMAScript 2018 .
Для глубокого клонирования вам понадобится другое решение .
const clone = {...original}
клонировать
const newobj = {...original, prop: newOne}
непременно добавьте другую опору к оригиналу и сохраните как новый объект.
JSON.parse(JSON.stringify(input))
JSON.parse(JSON.stringify(input))
не сработает, потому что если там functions
или infinity
как значения он просто назначит null
на их место. Это будет работать только в том случае, если значения просты, literals
а не functions
.
РЕДАКТИРОВАТЬ: Когда этот ответ был опубликован, {...obj}
синтаксис был недоступен в большинстве браузеров. В настоящее время, вы должны нормально использовать его (если вам не нужно поддерживать IE 11).
Используйте Object.assign.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
var obj = { a: 1 };
var copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }
Тем не менее, это не сделает глубокий клон. Пока нет родного способа глубокого клонирования.
РЕДАКТИРОВАТЬ: Как @Mike 'Pomax' Kamermans упомянул в комментариях, вы можете глубоко клонировать простые объекты (т.е. без прототипов, функций или циклических ссылок), используя JSON.parse(JSON.stringify(input))
JSON.parse(JSON.stringify(input))
это правильный глубокий клон. Однако в тот момент, когда прототипы, функции или циклические ссылки находятся в игре, это решение больше не работает.
Если используемые вами методы плохо работают с объектами, включающими такие типы данных, как Date , попробуйте это
Импортировать _
import * as _ from 'lodash';
Глубокий клон
myObjCopy = _.cloneDeep(myObj);
import _ from 'lodash';
достаточно. Но +1 за ответ "не изобретай велосипед".
если вы не хотите использовать json.parse (json.stringify (object)), вы можете создать рекурсивные копии со значением ключа:
function copy(item){
let result = null;
if(!item) return result;
if(Array.isArray(item)){
result = [];
item.forEach(element=>{
result.push(copy(element));
});
}
else if(item instanceof Object && !(item instanceof Function)){
result = {};
for(let key in item){
if(key){
result[key] = copy(item[key]);
}
}
}
return result || item;
}
Но лучший способ - создать класс, который может сам возвращать клон
class MyClass{
data = null;
constructor(values){ this.data = values }
toString(){ console.log("MyClass: "+this.data.toString(;) }
remove(id){ this.data = data.filter(d=>d.id!==id) }
clone(){ return new MyClass(this.data) }
}
Следуя ответу @marcel, я обнаружил, что некоторые функции все еще отсутствуют в клонированном объекте. например
function MyObject() {
var methodAValue = null,
methodBValue = null
Object.defineProperty(this, "methodA", {
get: function() { return methodAValue; },
set: function(value) {
methodAValue = value || {};
},
enumerable: true
});
Object.defineProperty(this, "methodB", {
get: function() { return methodAValue; },
set: function(value) {
methodAValue = value || {};
}
});
}
где на MyObject я мог клонировать methodA, но methodB был исключен. Это произошло потому, что оно отсутствует
enumerable: true
что означало, что он не появился в
for(let key in item)
Вместо этого я переключился на
Object.getOwnPropertyNames(item).forEach((key) => {
....
});
который будет включать не перечисляемые ключи.
Я также обнаружил, что прототип ( proto ) не был клонирован. Для этого я использовал
if (obj.__proto__) {
copy.__proto__ = Object.assign(Object.create(Object.getPrototypeOf(obj)), obj);
}
PS: расстраивает, что не смог найти встроенную функцию для этого.
Вы можете сделать это так же,
let copiedData = JSON.parse(JSON.stringify(data));
We can do that with two way:
1- First create a new object and replicate the structure of the existing one by iterating
over its properties and copying them on the primitive level.
let user = {
name: "John",
age: 30
};
let clone = {}; // the new empty object
// let's copy all user properties into it
for (let key in user) {
clone[key] = user[key];
}
// now clone is a fully independant clone
clone.name = "Pete"; // changed the data in it
alert( user.name ); // still John in the original object
2- Second we can use the method Object.assign for that
let user = { name: "John" };
let permissions1 = { canView: true };
let permissions2 = { canEdit: true };
// copies all properties from permissions1 and permissions2 into user
Object.assign(user, permissions1, permissions2);
-Another example
let user = {
name: "John",
age: 30
};
let clone = Object.assign({}, user);
It copies all properties of user into the empty object and returns it. Actually, the same as the loop, but shorter.
Но Object.assign () не создает глубокий клон
let user = {
name: "John",
sizes: {
height: 182,
width: 50
}
};
let clone = Object.assign({}, user);
alert( user.sizes === clone.sizes ); // true, same object
// user and clone share sizes
user.sizes.width++; // change a property from one place
alert(clone.sizes.width); // 51, see the result from the other one
Чтобы исправить это, мы должны использовать цикл клонирования, который проверяет каждое значение user [key] и, если это объект, затем копирует его структуру. Это называется «глубокое клонирование».
Существует стандартный алгоритм глубокого клонирования, который обрабатывает описанный выше случай и более сложные случаи, называемый алгоритмом структурированного клонирования . Чтобы не изобретать велосипед, мы можем использовать рабочую реализацию из библиотеки JavaScript lodash метод называется _.cloneDeep (объект) .
Все описанные выше методы не обрабатывают глубокое клонирование объектов, если оно вложено в n уровней. Я не проверял его производительность по сравнению с другими, но он короткий и простой.
В первом примере ниже показано клонирование объектов с использованием Object.assign
клонов до первого уровня.
var person = {
name:'saksham',
age:22,
skills: {
lang:'javascript',
experience:5
}
}
newPerson = Object.assign({},person);
newPerson.skills.lang = 'angular';
console.log(newPerson.skills.lang); //logs Angular
Используя приведенный ниже подход, глубоко клонируем объект
var person = {
name:'saksham',
age:22,
skills: {
lang:'javascript',
experience:5
}
}
anotherNewPerson = JSON.parse(JSON.stringify(person));
anotherNewPerson.skills.lang = 'angular';
console.log(person.skills.lang); //logs javascript
original = { a: [1,2,3] }
дает вам клон сclone.a
буквально существомoriginal.a
. Модификация не с помощью либоclone
илиoriginal
модифицирует одно и то же , так что нет, это плохо =)