Во многих ситуациях вы можете захотеть использовать, .copy()но на самом деле это не понадобится. В различных проектах AngJS1, которые я видел, это было излишним, когда для более чистого кода было бы сделано ручное копирование соответствующих подструктур. Возможно, это было частью решения не реализовывать его командой Angular.
Предполагая, что вы используете ES6, вы можете использовать var copy = Object.assign({}, original). Работает в современных браузерах; если вам нужна поддержка старых браузеров, ознакомьтесь с этим полифилом
Обновить:
В TypeScript 2.1+ доступна сокращенная нотация распространения объектов ES6:
Обратите внимание, что angular.copy()создает глубокую копию вопреки Object.assign(). Если вы хотите глубоко копия использование lodash _.cloneDeep(value)lodash.com/docs#cloneDeep
bertrandg
в Webstorm попал Unresolved function or method assign(); Сведения об IDE: Webstorm 2016.2. Как я могу это решить?
mihai 08
2
@meorfi Перейти к File -> Settings -> Languages & Frameworks -> Javascriptи набор Javascript language versionк ECMAScript 6.0.
Siri0S
@bertrandg _.clone (value) отличается от angular.copy (), он не будет создавать новый экземпляр, поэтому, поскольку _.cloneDeep (value) по-прежнему создает ссылку stackoverflow.com/questions/26411754/…
Zealitude
5
Кроме того, если вы копируете массив, используйте:const copy = [ ...original ]
daleyjem
43
Пока у нас не будет лучшего решения, вы можете использовать следующее:
Обратите внимание: вышеприведенное решение предназначалось только для быстрого исправления одного лайнера, предоставленного в то время, когда Angular 2 находился в активной разработке. Я надеялся, что в конце концов мы сможем получить эквивалент angular.copy(). Поэтому я не хотел писать или импортировать библиотеку глубокого клонирования.
У этого метода также есть проблемы с анализом свойств даты (он станет строкой).
Пожалуйста, не используйте этот метод в рабочих приложениях . Используйте его только в своих экспериментальных проектах - тех, которые вы делаете для изучения Angular 2.
это портит ваши свидания и идет чертовски медленно.
LanderV
5
Не так медленно, как импорт всей библиотеки для выполнения одной задачи, если то, что вы делаете, довольно просто ...
Ян Белчер,
1
это ужасно, никогда не используйте это
Мурхаф Сусли
1
@MurhafSousli, пожалуйста, постарайтесь понять контекст этого ответа. Это было предусмотрено, когда Angular 2 находился в стадии разработки, и мы надеялись, что в конечном итоге мы получим эквивалент функции angular.copy (). Чтобы сократить период ожидания, я предлагаю это решение в качестве временного варианта, пока у нас не будет лучшего решения. Это однострочник с глубоким клонированием. Я согласен, это ужасно ... Но, учитывая экспериментальный контекст того времени, это не так уж и плохо.
Mani
1
@ LazarLjubenović, конечно, в 2018 году это так, и я полностью согласен с вами сегодня , но в 2016 году в веб-пакете не было дрожания дерева, поэтому в большинстве случаев вы импортировали бы целую библиотеку.
Ян Белчер
22
Альтернативой глубокому копированию объектов, содержащих вложенные объекты, является использование метода lodash cloneDeep.
Для Angular это можно сделать так:
Установите lodash с помощью yarn add lodashили npm install lodash.
В своем компоненте импортируйте cloneDeepи используйте его:
import { cloneDeep } from "lodash";
...
clonedObject = cloneDeep(originalObject);
В вашу сборку добавлено всего 18 КБ, что стоит того.
Я также написал здесь статью , если вам нужно больше информации о том, зачем использовать lodash cloneDeep.
"только 18kb" добавлено к выводу, чтобы просто иметь возможность глубокого копирования объектов? JavaScript - это беспорядок.
Эндрю
После прочтения указанной статьи я понял, что cloneDeepметод создает экземпляр нового объекта. Стоит ли нам по-прежнему использовать его, если у нас уже есть целевой объект?
Стефан
17
Для неглубокого копирования вы можете использовать Object.assign, который является функцией ES6.
let x = { name: 'Marek', age: 20 };
let y = Object.assign({}, x);
x === y; //false
Что можно использовать для глубокого клонирования?
DB
15
Используйте lodash, как указано bertandg. Причина, по которой angular больше не имеет этого метода, заключается в том, что angular 1 был автономной структурой, и внешние библиотеки часто сталкивались с проблемами с контекстом выполнения angular. Angular 2 не имеет этой проблемы, поэтому используйте любую библиотеку, которую хотите.
Если вы хотите скопировать экземпляр класса, вы также можете использовать Object.assign, но вам нужно передать новый экземпляр в качестве первого параметра (вместо {}):
class MyClass {
public prop1: number;
public prop2: number;
public summonUnicorn(): void {
alert('Unicorn !');
}
}
let instance = new MyClass();
instance.prop1 = 12;
instance.prop2 = 42;
let wrongCopy = Object.assign({}, instance);
console.log(wrongCopy.prop1); // 12
console.log(wrongCopy.prop2); // 42
wrongCopy.summonUnicorn() // ERROR : undefined is not a function
let goodCopy = Object.assign(new MyClass(), instance);
console.log(goodCopy.prop1); // 12
console.log(goodCopy.prop2); // 42
goodCopy.summonUnicorn() // It works !
Как уже отмечали другие, использование lodash или подчеркивания, вероятно, является лучшим решением. Но если вам не нужны эти библиотеки ни для чего другого, вы, вероятно, можете использовать что-то вроде этого:
function deepClone(obj) {
// return value is input is not an Object or Array.
if (typeof(obj) !== 'object' || obj === null) {
return obj;
}
let clone;
if(Array.isArray(obj)) {
clone = obj.slice(); // unlink Array reference.
} else {
clone = Object.assign({}, obj); // Unlink Object reference.
}
let keys = Object.keys(clone);
for (let i=0; i<keys.length; i++) {
clone[keys[i]] = deepClone(clone[keys[i]]); // recursively unlink reference to nested objects.
}
return clone; // return unlinked clone.
}
// для отмены связи дат мы можем добавить: if (Object.prototype.toString.call (obj) === '[object Date]') {return new Date (obj.getTime ()); }
A_J 07
1
или проверьте дату, используя тип экземпляра - if (obj instanceof Date) {return new Date (obj.getTime ())}
Anoop Isaac
0
Мне эта функция нужна была просто для формирования «моделей» моего приложения (необработанные данные серверной части, преобразованные в объекты). В итоге я использовал комбинацию Object.create (создание нового объекта из указанного прототипа) и Object.assign (копирование свойств между объектами). Необходимо обрабатывать глубокую копию вручную. Я создал для этого суть .
Я создал сервис для использования с Angular 5 или выше, он использует angular.copy ()базу angularjs, мне он подходит. Кроме того, есть другие функции, например isUndefined, и т. Д. Надеюсь, это поможет. Как и любая оптимизация, было бы неплохо узнать. С уважением
import{Injectable}from'@angular/core';@Injectable({providedIn:'root'})exportclassAngularService{private TYPED_ARRAY_REGEXP =/^\[object (?:Uint8|Uint8Clamped|Uint16|Uint32|Int8|Int16|Int32|Float32|Float64)Array\]$/;private stackSource =[];private stackDest =[];constructor(){}public isNumber(value: any): boolean {if(typeof value ==='number'){returntrue;}else{returnfalse;}}public isTypedArray(value: any){return value &&this.isNumber(value.length)&&this.TYPED_ARRAY_REGEXP.test(toString.call(value));}public isArrayBuffer(obj: any){return toString.call(obj)==='[object ArrayBuffer]';}public isUndefined(value: any){returntypeof value ==='undefined';}public isObject(value: any){return value !==null&&typeof value ==='object';}public isBlankObject(value: any){return value !==null&&typeof value ==='object'&&!Object.getPrototypeOf(value);}public isFunction(value: any){returntypeof value ==='function';}public setHashKey(obj: any, h: any){if(h){ obj.$$hashKey = h;}else{delete obj.$$hashKey;}}private isWindow(obj: any){return obj && obj.window === obj;}private isScope(obj: any){return obj && obj.$evalAsync && obj.$watch;}private copyRecurse(source: any, destination: any){const h = destination.$$hashKey;if(Array.isArray(source)){for(let i =0, ii = source.length; i < ii; i++){
destination.push(this.copyElement(source[i]));}}elseif(this.isBlankObject(source)){for(const key ofObject.keys(source)){
destination[key]=this.copyElement(source[key]);}}elseif(source &&typeof source.hasOwnProperty ==='function'){for(const key ofObject.keys(source)){
destination[key]=this.copyElement(source[key]);}}else{for(const key ofObject.keys(source)){
destination[key]=this.copyElement(source[key]);}}this.setHashKey(destination, h);return destination;}private copyElement(source: any){if(!this.isObject(source)){return source;}const index =this.stackSource.indexOf(source);if(index !==-1){returnthis.stackDest[index];}if(this.isWindow(source)||this.isScope(source)){throw console.log('Cant copy! Making copies of Window or Scope instances is not supported.');}let needsRecurse =false;let destination =this.copyType(source);if(destination ===undefined){
destination =Array.isArray(source)?[]:Object.create(Object.getPrototypeOf(source));
needsRecurse =true;}this.stackSource.push(source);this.stackDest.push(destination);return needsRecurse
?this.copyRecurse(source, destination): destination;}private copyType =(source: any)=>{switch(toString.call(source)){case'[object Int8Array]':case'[object Int16Array]':case'[object Int32Array]':case'[object Float32Array]':case'[object Float64Array]':case'[object Uint8Array]':case'[object Uint8ClampedArray]':case'[object Uint16Array]':case'[object Uint32Array]':returnnew source.constructor(this.copyElement(source.buffer), source.byteOffset, source.length);case'[object ArrayBuffer]':if(!source.slice){const copied =newArrayBuffer(source.byteLength);newUint8Array(copied).set(newUint8Array(source));return copied;}return source.slice(0);case'[object Boolean]':case'[object Number]':case'[object String]':case'[object Date]':returnnew source.constructor(source.valueOf());case'[object RegExp]':const re =newRegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
re.lastIndex = source.lastIndex;return re;case'[object Blob]':returnnew source.constructor([source],{type: source.type});}if(this.isFunction(source.cloneNode)){return source.cloneNode(true);}}public copy(source: any, destination?: any){if(destination){if(this.isTypedArray(destination)||this.isArrayBuffer(destination)){throw console.log('Cant copy! TypedArray destination cannot be mutated.');}if(source === destination){throw console.log('Cant copy! Source and destination are identical.');}if(Array.isArray(destination)){
destination.length =0;}else{
destination.forEach((value: any, key: any)=>{if(key !=='$$hashKey'){delete destination[key];}});}this.stackSource.push(source);this.stackDest.push(destination);returnthis.copyRecurse(source, destination);}returnthis.copyElement(source);}}
Я, как и вы, столкнулся с проблемой работы angular.copy и angular.expect, потому что они не копируют объект и не создают объект без добавления некоторых зависимостей. Мое решение было таким:
Если вы еще не используете lodash, я бы не рекомендовал устанавливать его только для этого метода. Вместо этого я предлагаю более узкую специализированную библиотеку, такую как «клон»:
.copy()
но на самом деле это не понадобится. В различных проектах AngJS1, которые я видел, это было излишним, когда для более чистого кода было бы сделано ручное копирование соответствующих подструктур. Возможно, это было частью решения не реализовывать его командой Angular.Ответы:
Предполагая, что вы используете ES6, вы можете использовать
var copy = Object.assign({}, original)
. Работает в современных браузерах; если вам нужна поддержка старых браузеров, ознакомьтесь с этим полифиломОбновить:
В TypeScript 2.1+ доступна сокращенная нотация распространения объектов ES6:
источник
angular.copy()
создает глубокую копию вопрекиObject.assign()
. Если вы хотите глубоко копия использование lodash_.cloneDeep(value)
lodash.com/docs#cloneDeepUnresolved function or method assign()
; Сведения об IDE: Webstorm 2016.2. Как я могу это решить?File -> Settings -> Languages & Frameworks -> Javascript
и наборJavascript language version
кECMAScript 6.0
.const copy = [ ...original ]
Пока у нас не будет лучшего решения, вы можете использовать следующее:
РЕДАКТИРОВАТЬ: Разъяснение
Обратите внимание: вышеприведенное решение предназначалось только для быстрого исправления одного лайнера, предоставленного в то время, когда Angular 2 находился в активной разработке. Я надеялся, что в конце концов мы сможем получить эквивалент
angular.copy()
. Поэтому я не хотел писать или импортировать библиотеку глубокого клонирования.У этого метода также есть проблемы с анализом свойств даты (он станет строкой).
Пожалуйста, не используйте этот метод в рабочих приложениях . Используйте его только в своих экспериментальных проектах - тех, которые вы делаете для изучения Angular 2.
источник
Альтернативой глубокому копированию объектов, содержащих вложенные объекты, является использование метода lodash cloneDeep.
Для Angular это можно сделать так:
Установите lodash с помощью
yarn add lodash
илиnpm install lodash
.В своем компоненте импортируйте
cloneDeep
и используйте его:В вашу сборку добавлено всего 18 КБ, что стоит того.
Я также написал здесь статью , если вам нужно больше информации о том, зачем использовать lodash cloneDeep.
источник
cloneDeep
метод создает экземпляр нового объекта. Стоит ли нам по-прежнему использовать его, если у нас уже есть целевой объект?Для неглубокого копирования вы можете использовать Object.assign, который является функцией ES6.
НЕ используйте его для глубокого клонирования
источник
Используйте lodash, как указано bertandg. Причина, по которой angular больше не имеет этого метода, заключается в том, что angular 1 был автономной структурой, и внешние библиотеки часто сталкивались с проблемами с контекстом выполнения angular. Angular 2 не имеет этой проблемы, поэтому используйте любую библиотеку, которую хотите.
https://lodash.com/docs#cloneDeep
источник
Если вы хотите скопировать экземпляр класса, вы также можете использовать Object.assign, но вам нужно передать новый экземпляр в качестве первого параметра (вместо {}):
источник
Самое простое решение, которое я нашел:
* ВАЖНЫЕ ШАГИ: вы должны установить lodash, чтобы использовать это (что было неясно из других ответов):
а затем импортируйте его в свой ts файл:
источник
Как уже отмечали другие, использование lodash или подчеркивания, вероятно, является лучшим решением. Но если вам не нужны эти библиотеки ни для чего другого, вы, вероятно, можете использовать что-то вроде этого:
Вот что мы решили сделать.
источник
Мне эта функция нужна была просто для формирования «моделей» моего приложения (необработанные данные серверной части, преобразованные в объекты). В итоге я использовал комбинацию Object.create (создание нового объекта из указанного прототипа) и Object.assign (копирование свойств между объектами). Необходимо обрабатывать глубокую копию вручную. Я создал для этого суть .
источник
Была такая же проблема, и я не хотел использовать какие-либо плагины только для глубокого клонирования:
Кредиты: я сделал эту функцию более читаемой , пожалуйста, проверьте исключения из ее функциональности ниже
источник
Я создал сервис для использования с Angular 5 или выше, он использует
angular.copy ()
базу angularjs, мне он подходит. Кроме того, есть другие функции, напримерisUndefined
, и т. Д. Надеюсь, это поможет. Как и любая оптимизация, было бы неплохо узнать. С уважениемисточник
Я, как и вы, столкнулся с проблемой работы angular.copy и angular.expect, потому что они не копируют объект и не создают объект без добавления некоторых зависимостей. Мое решение было таким:
источник
JSON.stringify()
Метод преобразует объект JavaScript или значение в строку JSONисточник
Вы можете клонировать массив как
И клонировать объект как
источник
Если вы еще не используете lodash, я бы не рекомендовал устанавливать его только для этого метода. Вместо этого я предлагаю более узкую специализированную библиотеку, такую как «клон»:
источник