Гуглінг для "об’єкта клонування 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
змінює те саме , так що ні, це погано =)