Гуглінг для "об’єкта клонування JavaScript" приносить деякі дійсно дивні результати, деякі з них безнадійно застаріли, а деякі просто занадто складні, чи не так просто, як просто:
let clone = {...original};
Чи щось з цим не так?
Гуглінг для "об’єкта клонування JavaScript" приносить деякі дійсно дивні результати, деякі з них безнадійно застаріли, а деякі просто занадто складні, чи не так просто, як просто:
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.
EDIT: Коли ця відповідь була розміщена, {...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 }
Однак це не зробить глибокого клону. На сьогодні не існує рідного способу глибокого клонування.
EDIT: Як згадується у коментарях @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 я міг клонувати методA, але метод B був виключений. Це сталося тому, що він відсутній
enumerable: true
що означало, що він не з'явився в
for(let key in item)
Натомість я перейшов на
Object.getOwnPropertyNames(item).forEach((key) => {
....
});
який буде включати не перелічувані ключі.
Я також виявив, що прототип ( прото ) не був клонований. Для цього я закінчила використовувати
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
Щоб виправити це, нам слід скористатися циклом клонування, який вивчає кожне значення користувача [key], і, якщо це об’єкт, а також повторити його структуру. Це називається "глибоким клонуванням".
Існує стандартний алгоритм глибокого клонування, який обробляє випадок вище та складніші випадки, званий алгоритмом структурного клонування . Щоб не винаходити колесо, ми можемо використовувати робочу реалізацію його з бібліотеки JavaScript lodash, метод називається _.cloneDeep (obj) .
Усі наведені вище методи не обробляють глибоке клонування об'єктів, де вони вкладені до 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змінює те саме , так що ні, це погано =)