Решение конкретной проблемы
Вы можете использовать утверждение типа, чтобы сообщить компилятору, что вы знаете лучше:
public clone(): any {
var cloneObj = new (this.constructor() as any);
for (var attribut in this) {
if (typeof this[attribut] === "object") {
cloneObj[attribut] = this[attribut].clone();
} else {
cloneObj[attribut] = this[attribut];
}
}
return cloneObj;
}
клонирование
Имейте в виду, что иногда лучше написать собственное отображение, чем быть полностью динамичным. Тем не менее, есть несколько приемов «клонирования», которые вы можете использовать, которые дают вам эффекты разницы.
Я буду использовать следующий код для всех последующих примеров:
class Example {
constructor(public type: string) {
}
}
class Customer {
constructor(public name: string, public example: Example) {
}
greet() {
return 'Hello ' + this.name;
}
}
var customer = new Customer('David', new Example('DavidType'));
Вариант 1: распространение
Свойства: Да
Методы: Нет
Глубокая копия: Нет
var clone = { ...customer };
alert(clone.name + ' ' + clone.example.type); // David DavidType
//alert(clone.greet()); // Not OK
clone.name = 'Steve';
clone.example.type = 'SteveType';
alert(customer.name + ' ' + customer.example.type); // David SteveType
Вариант 2: Object.assign
Свойства: Да
Методы: Нет
Глубокая копия: Нет
var clone = Object.assign({}, customer);
alert(clone.name + ' ' + clone.example.type); // David DavidType
alert(clone.greet()); // Not OK, although compiler won't spot it
clone.name = 'Steve';
clone.example.type = 'SteveType';
alert(customer.name + ' ' + customer.example.type); // David SteveType
Вариант 3: Object.create
Свойства: унаследованные
методы: унаследованный
Deep Copy: мелкий унаследованный (глубокие изменения влияют как на оригинал, так и на клон)
var clone = Object.create(customer);
alert(clone.name + ' ' + clone.example.type); // David DavidType
alert(clone.greet()); // OK
customer.name = 'Misha';
customer.example = new Example("MishaType");
// clone sees changes to original
alert(clone.name + ' ' + clone.example.type); // Misha MishaType
clone.name = 'Steve';
clone.example.type = 'SteveType';
// original sees changes to clone
alert(customer.name + ' ' + customer.example.type); // Misha SteveType
Вариант 4: функция глубокого копирования
Свойства: Да
Методы: Нет
Глубокая копия: Да
function deepCopy(obj) {
var copy;
// Handle the 3 simple types, and null or undefined
if (null == obj || "object" != typeof obj) return obj;
// Handle Date
if (obj instanceof Date) {
copy = new Date();
copy.setTime(obj.getTime());
return copy;
}
// Handle Array
if (obj instanceof Array) {
copy = [];
for (var i = 0, len = obj.length; i < len; i++) {
copy[i] = deepCopy(obj[i]);
}
return copy;
}
// Handle Object
if (obj instanceof Object) {
copy = {};
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = deepCopy(obj[attr]);
}
return copy;
}
throw new Error("Unable to copy obj! Its type isn't supported.");
}
var clone = deepCopy(customer) as Customer;
alert(clone.name + ' ' + clone.example.type); // David DavidType
// alert(clone.greet()); // Not OK - not really a customer
clone.name = 'Steve';
clone.example.type = 'SteveType';
alert(customer.name + ' ' + customer.example.type); // David DavidType
cloned instanceof MyClass === true
?1. Используйте спред оператора
Оператор Spread берет все поля из obj1 и распространяет их по obj2. В результате вы получите новый объект с новой ссылкой и теми же полями, что и исходный.
Помните, что это мелкая копия, это означает, что если объект является вложенным, то его вложенные составные параметры будут существовать в новом объекте по той же ссылке.
2.Object.assign ()
Object.assign создает реальную копию, но только собственные свойства, поэтому свойства в прототипе не будут существовать в скопированном объекте. Это также мелкая копия.
3.Object.create ()
Object.create
не занимается реальным клонированием , а создает объект из прототипа. Поэтому используйте его, если объект должен клонировать свойства основного типа, потому что назначение свойств основного типа не выполняется по ссылке.Плюсы Object.create в том , что любые функции, объявленные в прототипе, будут доступны в нашем недавно созданном объекте.
Несколько вещей о мелкой копии
Мелкая копия помещает в новый объект все поля старого, но это также означает, что если исходный объект имеет поля составного типа (объект, массивы и т. Д.), То эти поля помещаются в новый объект с теми же ссылками. Мутация такого поля в исходном объекте будет отражена в новом объекте.
Это может выглядеть как ловушка, но на самом деле ситуация, когда весь сложный объект должен быть скопирован, встречается редко. Малая копия будет повторно использовать большую часть памяти, что означает, что это очень дешево по сравнению с глубокой копией.
Глубокая копия
Оператор спреда может быть полезен для глубокого копирования.
Выше кода создана глубокая копия obj1. Составное поле «комплекс» также было скопировано в obj2. Мутация поля «сложный» не будет отражать копию.
источник
Object.create(obj1)
создает новый объект и назначает obj1 в качестве прототипа. Ни одно из полей в obj1 не копируется и не клонируется. Таким образом, изменения в obj1 без изменения obj2 будут видны, так как он по существу не имеет свойств. Если вы сначала измените obj2, то прототип не будет виден для поля, которое вы определяете, так как поле obj2 с именем находится ближе в иерархии.let b = Object.assign({}, a);
Попробуй это:
Это хорошее решение, пока вы не используете очень большие объекты или если ваш объект не обладает сериализуемыми свойствами.
Чтобы сохранить безопасность типов, вы можете использовать функцию копирования в классе, из которого вы хотите делать копии:
или статическим способом:
источник
undefined
значением, по крайней мере. еслиobjectToCopy = { x : undefined};
после запуска ваш кодObject.keys(objectToCopy).length
есть1
, то покаObject.keys(copy).length
есть0
.TypeScript / JavaScript имеет свой собственный оператор для мелкого клонирования:
источник
Легко получить поверхностную копию с помощью «Object Spread», представленного в TypeScript 2.1
этот TypeScript:
let copy = { ...original };
производит этот JavaScript:
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html
источник
Для сериализуемого глубокого клона, с информацией о типе
источник
JSON.stringify
clone
. :)undefined
значением. См. Мой комментарий к аналогичному ответу выше: stackoverflow.com/questions/28150967/typescript-cloning-object/…Мой взгляд на это:
Object.assign(...)
только копирует свойства и мы теряем прототип и методы.Object.create(...)
не копирует свойства для меня, а просто создает прототип.Для меня сработало создание прототипа с использованием
Object.create(...)
и копирование свойств в него с помощьюObject.assign(...)
:Итак, для объекта
foo
сделайте клон следующим образом:источник
foo
становитесь прототипом родителяclonedFoo
(нового объекта). Хотя это может звучать нормально, вы должны иметь в виду, что пропущенное свойство будет найдено в цепочке прототипов, поэтомуconst a = { x: 8 }; const c = Object.assign(Object.create(a), a); delete c.x; console.log(c.x);
выводит 8, а должно бытьundefined
! (Ссылка REPL: repl.it/repls/CompetitivePreemptiveKeygen )foo
, оно автоматически отобразится дляclonedFoo
! напримерfoo.y = 9; console.log(clonedFoo.y)
, распечатает9
вместоundefined
. Очень вероятно, что это не то, что вы просите!Вы также можете иметь что-то вроде этого:
Просто убедитесь, что вы переопределяете
clone
метод во всехEntity
подклассах, иначе вы получите частичные клоны.Тип возвращаемого значения
this
всегда будет соответствовать типу экземпляра.источник
Добавьте
"lodash.clonedeep": "^4.5.0"
к своемуpackage.json
. Тогда используйте как это:источник
Вот мое пюре! И вот ссылка на StackBlitz к нему. В настоящее время он ограничен только копированием простых типов и типов объектов, но я мог бы подумать, что его можно легко изменить.
источник
typeof null
это также объект, поэтому запрос должен бытьif (source[P] !== null && typeof source[P] === 'object')
вместо. В противном случае ваши нулевые значения превратятся в пустой объект.Если вы получили эту ошибку:
Это правильный сценарий:
источник
cloneObj[attribut] = this.clone();
? или вы имеете в видуcloneObj[attribut] = this[attribut].clone();
Сам столкнулся с этой проблемой и в конце написал небольшую библиотеку cloneable-ts, которая предоставляет абстрактный класс, который добавляет метод клонирования к любому классу, расширяющему его. Абстрактный класс заимствует функцию Deep Copy , описанную в общепринятом ответе на Фентоне только замену
copy = {};
с ,copy = Object.create(originalObj)
чтобы сохранить класс исходного объекта. Вот пример использования класса.Или вы можете просто использовать
Cloneable.clone
вспомогательный метод:источник
Поскольку выпущен TypeScript 3.7, теперь поддерживаются рекурсивные псевдонимы типов , и это позволяет нам определять функцию безопасного типа
deepCopy()
:Игровая площадка
источник
Для простого клонирования содержимого объекта дыры я просто строжайся и анализирую экземпляр:
В то время как я изменяю данные в дереве objectToClone, в cloneObject нет никаких изменений. Это было мое требование.
Надеюсь, это поможет
источник
undefined
значением. См. Мой комментарий к аналогичному ответу выше: stackoverflow.com/questions/28150967/typescript-cloning-object/…Я закончил тем, что сделал:
Так как:
от @Fenton дал ошибки во время выполнения.
Версия машинописного текста: 2.4.2
источник
Как насчет старого доброго jQuery ?! Вот глубокий клон:
источник
Я попытался создать общий сервис копирования / клонирования, который сохраняет типы для вложенных объектов. Хотелось бы получить обратную связь, если я делаю что-то не так, но, похоже, до сих пор работает ...
источник
В typeScript я тестирую с angular, и все нормально
источник
Для глубокого клонирования объекта, который может содержать другие объекты, массивы и т. Д., Я использую:
Использование:
источник
Вы можете использовать деструктурирующее присваивание с расширенным синтаксисом :
источник
Вот современная реализация, которая учитывает
Set
и то иMap
другое:Опробовать это:
источник
Если у вас уже есть целевой объект, поэтому вы не хотите создавать его заново (как, например, при обновлении массива), вы должны скопировать свойства.
Если сделали это так:
Хвала должная. (посмотрите на заголовок "версия 2")
источник