Vérifiez cette solution, cela pourrait aider: Lien
Nourdine Alouane
Dans de nombreuses situations, vous voudrez peut-être l'utiliser .copy()mais n'en auriez pas besoin. Dans divers projets AngJS1 que j'ai vus, c'était une exagération, où une copie manuelle des sous-structures pertinentes aurait permis un code plus propre. Peut-être que cela faisait partie de la décision de ne pas l'implémenter par l'équipe Angular.
En supposant que vous utilisez ES6, vous pouvez utiliser var copy = Object.assign({}, original). Fonctionne dans les navigateurs modernes; si vous avez besoin de prendre en charge des navigateurs plus anciens, consultez ce polyfill
mettre à jour:
Avec TypeScript 2.1+, la notation d'étalement d'objet abrégée ES6 est disponible:
Notez que angular.copy()crée une copie profonde contrairement à Object.assign(). Si vous voulez une copie profonde, utilisez lodash _.cloneDeep(value)lodash.com/docs#cloneDeep
bertrandg
dans Webstorm j'ai eu Unresolved function or method assign(); Détails de l'EDI: Webstorm 2016.2. Comment puis-je résoudre ça?
mihai
2
@meorfi Accédez à File -> Settings -> Languages & Frameworks -> Javascriptet réglez Javascript language versionsur ECMAScript 6.0.
Siri0S
@bertrandg _.clone (valeur) est différent de angular.copy (), il ne créera pas de nouvelle instance, donc comme _.cloneDeep (valeur), il créera toujours une référence stackoverflow.com/questions/26411754
...
5
De plus, si vous copiez un tableau, utilisez:const copy = [ ...original ]
daleyjem
43
Jusqu'à ce que nous ayons une meilleure solution, vous pouvez utiliser les éléments suivants:
Remarque: la solution ci-dessus était uniquement destinée à être une solution rapide à une seule doublure, fournie à un moment où Angular 2 était en développement actif. J'espérais que nous pourrions éventuellement obtenir un équivalent de angular.copy(). Par conséquent, je ne voulais pas écrire ou importer une bibliothèque de clonage profond.
Cette méthode a également des problèmes avec l'analyse des propriétés de date (elle deviendra une chaîne).
Veuillez ne pas utiliser cette méthode dans les applications de production . Utilisez-le uniquement dans vos projets expérimentaux - ceux que vous faites pour apprendre Angular 2.
cela ruine vos rendez-vous et est lent comme l'enfer.
LanderV
5
Pas aussi lent que d'importer une bibliothèque entière pour faire une seule tâche, tant que ce que vous faites est assez simple ...
Ian Belcher
1
c'est horrible, ne jamais utiliser ça
Murhaf Sousli
1
@MurhafSousli veuillez essayer de comprendre le contexte de cette réponse. Cela a été fourni lorsque Angular 2 était en cours de développement, et l'espoir était que nous obtiendrons éventuellement un équivalent de la fonction angular.copy (). Pour combler la période d'attente, j'ai proposé cette solution comme option temporaire jusqu'à ce que nous ayons une meilleure solution. Il s'agit d'un one-liner avec un clonage profond. C'est horrible , je suis d'accord ... Mais étant donné le contexte expérimental de l'époque, ce n'est pas si mal.
Mani
1
@ LazarLjubenović bien sûr en 2018, c'est le cas et je suis tout à fait d'accord avec vous aujourd'hui , mais en 2016, le webpack n'avait pas d'arbre tremblant, vous importeriez donc une bibliothèque entière dans la plupart des cas.
Ian Belcher
22
L'alternative pour copier en profondeur des objets ayant des objets imbriqués à l'intérieur consiste à utiliser la méthode cloneDeep de lodash.
Pour Angular, vous pouvez le faire comme ceci:
Installez lodash avec yarn add lodashou npm install lodash.
Dans votre composant, importez-le cloneDeepet utilisez-le:
import { cloneDeep } from "lodash";
...
clonedObject = cloneDeep(originalObject);
Il ne s'agit que de 18 Ko ajoutés à votre build, ce qui en vaut la peine.
J'ai également écrit un article ici , si vous avez besoin de plus d'informations sur l'utilisation de cloneDeep de lodash.
"seulement 18 ko" ajouté à la sortie pour pouvoir simplement copier des objets en profondeur? JavaScript est un gâchis.
Endrju le
Après avoir lu votre article référencé, je comprends que la cloneDeepméthode instancie un nouvel objet. Devrions-nous continuer à l'utiliser si nous avons déjà un objet de destination?
Stéphane
17
Pour la copie superficielle, vous pouvez utiliser Object.assign qui est une fonctionnalité ES6
let x = { name: 'Marek', age: 20 };
let y = Object.assign({}, x);
x === y; //false
Utilisez le lodash comme indiqué par bertandg. La raison pour laquelle angular n'a plus cette méthode est que angular 1 était un framework autonome et que les bibliothèques externes rencontraient souvent des problèmes avec le contexte d'exécution angulaire. Angular 2 n'a pas ce problème, alors utilisez la bibliothèque de votre choix.
Si vous souhaitez copier une instance de classe, vous pouvez également utiliser Object.assign, mais vous devez passer une nouvelle instance comme premier paramètre (au lieu de {}):
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 !
Comme d'autres l'ont déjà souligné, l'utilisation de lodash ou de soulignement est probablement la meilleure solution. Mais si vous n'avez pas besoin de ces bibliothèques pour autre chose, vous pouvez probablement utiliser quelque chose comme ceci:
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.
}
// pour dissocier les dates, nous pouvons ajouter: if (Object.prototype.toString.call (obj) === '[object Date]') {return new Date (obj.getTime ()); }
A_J
1
ou vérifiez la date en utilisant le type d'instance - if (obj instanceof Date) {return new Date (obj.getTime ())}
Anoop Isaac
0
J'avais besoin de cette fonctionnalité pour former simplement mes `` modèles '' d'application (données brutes de backend converties en objets). J'ai donc fini par utiliser une combinaison de Object.create (créer un nouvel objet à partir du prototype spécifié) et Object.assign (copier les propriétés entre les objets). Besoin de gérer la copie complète manuellement. J'ai créé l' essentiel pour cela.
J'ai créé un service à utiliser avec Angular 5 ou supérieur, il utilise la angular.copy ()base d'angularjs, cela fonctionne bien pour moi. De plus, il existe d'autres fonctions comme isUndefined, etc. J'espère que cela aide. Comme toute optimisation, ce serait bien à savoir. Cordialement
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);}}
Moi aussi que vous faisiez face à un problème de travail angular.copy et angular.expect car ils ne copient pas l'objet ou ne créent pas l'objet sans ajouter quelques dépendances. Ma solution était la suivante:
Si vous n'utilisez pas déjà lodash, je ne recommanderais pas de l'installer uniquement pour cette méthode. Je suggère plutôt une bibliothèque plus étroitement spécialisée telle que 'clone':
.copy()
mais n'en auriez pas besoin. Dans divers projets AngJS1 que j'ai vus, c'était une exagération, où une copie manuelle des sous-structures pertinentes aurait permis un code plus propre. Peut-être que cela faisait partie de la décision de ne pas l'implémenter par l'équipe Angular.Réponses:
En supposant que vous utilisez ES6, vous pouvez utiliser
var copy = Object.assign({}, original)
. Fonctionne dans les navigateurs modernes; si vous avez besoin de prendre en charge des navigateurs plus anciens, consultez ce polyfillmettre à jour:
Avec TypeScript 2.1+, la notation d'étalement d'objet abrégée ES6 est disponible:
la source
angular.copy()
crée une copie profonde contrairement àObject.assign()
. Si vous voulez une copie profonde, utilisez lodash_.cloneDeep(value)
lodash.com/docs#cloneDeepUnresolved function or method assign()
; Détails de l'EDI: Webstorm 2016.2. Comment puis-je résoudre ça?File -> Settings -> Languages & Frameworks -> Javascript
et réglezJavascript language version
surECMAScript 6.0
.const copy = [ ...original ]
Jusqu'à ce que nous ayons une meilleure solution, vous pouvez utiliser les éléments suivants:
EDIT: Clarification
Remarque: la solution ci-dessus était uniquement destinée à être une solution rapide à une seule doublure, fournie à un moment où Angular 2 était en développement actif. J'espérais que nous pourrions éventuellement obtenir un équivalent de
angular.copy()
. Par conséquent, je ne voulais pas écrire ou importer une bibliothèque de clonage profond.Cette méthode a également des problèmes avec l'analyse des propriétés de date (elle deviendra une chaîne).
Veuillez ne pas utiliser cette méthode dans les applications de production . Utilisez-le uniquement dans vos projets expérimentaux - ceux que vous faites pour apprendre Angular 2.
la source
L'alternative pour copier en profondeur des objets ayant des objets imbriqués à l'intérieur consiste à utiliser la méthode cloneDeep de lodash.
Pour Angular, vous pouvez le faire comme ceci:
Installez lodash avec
yarn add lodash
ounpm install lodash
.Dans votre composant, importez-le
cloneDeep
et utilisez-le:Il ne s'agit que de 18 Ko ajoutés à votre build, ce qui en vaut la peine.
J'ai également écrit un article ici , si vous avez besoin de plus d'informations sur l'utilisation de cloneDeep de lodash.
la source
cloneDeep
méthode instancie un nouvel objet. Devrions-nous continuer à l'utiliser si nous avons déjà un objet de destination?Pour la copie superficielle, vous pouvez utiliser Object.assign qui est une fonctionnalité ES6
NE PAS l'utiliser pour le clonage profond
la source
Utilisez le lodash comme indiqué par bertandg. La raison pour laquelle angular n'a plus cette méthode est que angular 1 était un framework autonome et que les bibliothèques externes rencontraient souvent des problèmes avec le contexte d'exécution angulaire. Angular 2 n'a pas ce problème, alors utilisez la bibliothèque de votre choix.
https://lodash.com/docs#cloneDeep
la source
Si vous souhaitez copier une instance de classe, vous pouvez également utiliser Object.assign, mais vous devez passer une nouvelle instance comme premier paramètre (au lieu de {}):
la source
La solution la plus simple que j'ai trouvée est:
* ÉTAPES IMPORTANTES: Vous devez installer lodash pour utiliser ceci (ce qui n'était pas clair d'après les autres réponses):
puis importez-le dans votre fichier ts:
la source
Comme d'autres l'ont déjà souligné, l'utilisation de lodash ou de soulignement est probablement la meilleure solution. Mais si vous n'avez pas besoin de ces bibliothèques pour autre chose, vous pouvez probablement utiliser quelque chose comme ceci:
C'est ce que nous avons décidé de faire.
la source
J'avais besoin de cette fonctionnalité pour former simplement mes `` modèles '' d'application (données brutes de backend converties en objets). J'ai donc fini par utiliser une combinaison de Object.create (créer un nouvel objet à partir du prototype spécifié) et Object.assign (copier les propriétés entre les objets). Besoin de gérer la copie complète manuellement. J'ai créé l' essentiel pour cela.
la source
J'ai eu le même problème et je ne voulais pas utiliser de plugins uniquement pour le clonage en profondeur:
Crédits: j'ai rendu cette fonction plus lisible , veuillez vérifier les exceptions à sa fonctionnalité ci-dessous
la source
J'ai créé un service à utiliser avec Angular 5 ou supérieur, il utilise la
angular.copy ()
base d'angularjs, cela fonctionne bien pour moi. De plus, il existe d'autres fonctions commeisUndefined
, etc. J'espère que cela aide. Comme toute optimisation, ce serait bien à savoir. Cordialementla source
Moi aussi que vous faisiez face à un problème de travail angular.copy et angular.expect car ils ne copient pas l'objet ou ne créent pas l'objet sans ajouter quelques dépendances. Ma solution était la suivante:
la source
La
JSON.stringify()
méthode convertit un objet ou une valeur JavaScript en une chaîne JSONla source
Vous pouvez cloner le tableau comme
Et cloner l'objet comme
la source
Si vous n'utilisez pas déjà lodash, je ne recommanderais pas de l'installer uniquement pour cette méthode. Je suggère plutôt une bibliothèque plus étroitement spécialisée telle que 'clone':
la source