Maison >interface Web >js tutoriel >Copie profonde contre profonde dans JavaScript

Copie profonde contre profonde dans JavaScript

Jennifer Aniston
Jennifer Anistonoriginal
2025-02-09 08:28:10927parcourir

Shallow vs. Deep Copying in JavaScript

La copie d'objets JavaScript n'est pas aussi simple qu'il n'y paraît. Comprendre le fonctionnement des objets et des références au cours de ce processus pour les développeurs Web et peut économiser des heures de débogage. Cela devient de plus en plus important lorsque vous utilisez de grandes applications avec état, telles que celles intégrées à React ou Vue.

Copie peu profonde et copie profonde se référons à la façon dont nous créons des copies d'objets en javascript et sur les données que nous créons dans "Copier". Dans cet article, nous approfondirons les différences entre ces méthodes, explorerons leurs applications pratiques et découvrirons les pièges potentiels qui peuvent survenir lors de leur utilisation.

points clés

  • Une copie peu profonde dans JavaScript crée un nouvel objet qui copie les propriétés d'un objet existant, mais conserve la même référence à la valeur ou à l'objet d'origine. Cela signifie que les modifications des objets imbriqués dans des répliques peu profondes affectent également l'objet d'origine et toutes les autres répliques peu profondes.
  • En revanche, une copie profonde crée une copie exacte d'un objet existant, y compris toutes ses propriétés et tous les objets imbriqués, plutôt que de simples références. Cela rend la copie profonde bénéfique lorsque vous avez besoin de deux objets distincts qui ne partagent pas de références, garantissant que les modifications d'un objet n'affectent pas l'autre.
  • Bien que la réplication profonde offre les avantages de la précision des données, il peut également avoir des inconvénients tels que l'impact des performances, une consommation accrue de la mémoire, des problèmes de référence circulaire, une fonction et une manipulation spéciale d'objets et une complexité de mise en œuvre. Par conséquent, il est important d'évaluer si une réplication profonde est nécessaire pour chaque cas d'utilisation particulier.

Qu'est-ce que la copie "superficielle"

La copie superficielle fait référence au processus de création d'un nouvel objet, qui est une copie d'un objet existant dont les propriétés se réfèrent à la même valeur ou objet numérique que l'objet d'origine. En JavaScript, cela est généralement réalisé en utilisant des méthodes telles que Object.assign() ou syntaxe d'expansion ({...originalObject}). Une copie peu profonde ne crée que de nouvelles références à des objets ou des valeurs existants, et ne crée pas de copie profonde, ce qui signifie que les objets imbriqués sont toujours référencés, pas des doublons.

Jetons un coup d'œil à l'exemple de code suivant. L'objet nouvellement créé shallowCopyZoo est une copie de zoo créée en élargissant l'opérateur, qui a des conséquences inattendues.

<code class="language-javascript">let zoo = {
  name: "Amazing Zoo",
  location: "Melbourne, Australia",
  animals: [
    {
      species: "Lion",
      favoriteTreat: "?",
    },
    {
      species: "Panda",
      favoriteTreat: "?",
    },
  ],
};

let shallowCopyZoo = { ...zoo };
shallowCopyZoo.animals[0].favoriteTreat = "?";
console.log(zoo.animals[0].favoriteTreat); 
// "?",而不是 "?"</code>

Mais voyons ce qui est exactement dans shallowCopyZoo. Les propriétés name et location sont les valeurs d'origine (chaînes), donc leurs valeurs sont copiées. Cependant, la propriété animals est un tableau d'objets, donc ce qui est copié est une référence à ce tableau, pas au tableau lui-même.

Vous pouvez utiliser l'opérateur d'égalité strict (===) pour tester cela rapidement (si vous ne me croyez pas). Ce n'est que lorsqu'un objet fait référence au même objet, un objet est égal à un autre objet (voir Types de données primitifs et types de données de référence). Notez que les attributs animals sont égaux dans les deux, mais l'objet lui-même n'est pas égal.

<code class="language-javascript">let zoo = {
  name: "Amazing Zoo",
  location: "Melbourne, Australia",
  animals: [
    {
      species: "Lion",
      favoriteTreat: "?",
    },
    {
      species: "Panda",
      favoriteTreat: "?",
    },
  ],
};

let shallowCopyZoo = { ...zoo };
shallowCopyZoo.animals[0].favoriteTreat = "?";
console.log(zoo.animals[0].favoriteTreat); 
// "?",而不是 "?"</code>

Cela peut entraîner des problèmes potentiels dans la base de code et est particulièrement difficile lorsqu'il s'agit de grandes modifications. La modification des objets imbriqués dans des répliques peu profondes affecte également l'objet d'origine et toutes les autres répliques peu profondes car elles partagent toutes la même référence.

Copie profonde

La copie profonde est une astuce pour créer un nouvel objet qui est une copie exacte d'un objet existant. Cela comprend la copie de toutes ses propriétés et de tous les objets imbriqués, plutôt que des références. Le clonage profond est utile lorsque vous avez besoin de deux objets distincts qui ne partagent pas de références, garantissant que les modifications à un objet n'affectent pas l'autre.

Les programmeurs utilisent souvent un clonage profond lorsqu'ils traitent des objets d'état d'application dans des applications complexes. La création d'un nouvel objet d'état sans affecter l'état précédent est essentiel pour maintenir la stabilité des applications et implémenter correctement la fonctionnalité UNDO / Remo.

comment utiliser JSON.stringify() et JSON.parse() pour une copie profonde

Une méthode de copie profonde populaire et sans bibliothèque consiste à utiliser les méthodes intégrées JSON.stringify() et JSON.parse().

parse(stringify()) La méthode n'est pas parfaite. Par exemple, des types de données spéciaux tels que Date seront convertis en chaînes et les valeurs non définies seront ignorées. Comme pour toutes les options de cet article, vous devriez le considérer en fonction de votre cas d'utilisation spécifique.

Dans le code suivant, nous utiliserons ces méthodes pour créer une fonction deepCopy pour cloner profondément un objet. Ensuite, nous copie l'objet playerProfile et modifions l'objet copié sans affecter l'objet d'origine. Cela démontre la valeur de la réplication profonde dans le maintien d'objets indépendants qui ne partagent pas de références.

<code class="language-javascript">console.log(zoo.animals === shallowCopyZoo.animals)
// true

console.log(zoo === shallowCopyZoo)
// false</code>

bibliothèque pour la réplication profonde

Il existe également une variété de bibliothèques tierces qui fournissent des solutions de réplication profonde.

    Les fonctions
  • de la bibliothèque cloneDeep() Lodash peuvent gérer correctement les références de boucle, les fonctions et les objets spéciaux.
  • extend() Fonction de la bibliothèque jQuery [deep = true] La bibliothèque
  • immer est conçue pour les développeurs React-Redux et fournit des outils pratiques pour modifier les objets.
Vanilla JS Deep Copy Fonction

Si, pour une raison quelconque, vous ne souhaitez pas utiliser les objets JSON ou les bibliothèques tierces, vous pouvez également créer une fonction de copie profonde personnalisée dans Vanilla JavaScript. La fonction itère récursivement sur les propriétés des objets et crée un nouvel objet avec les mêmes propriétés et valeurs.

<code class="language-javascript">const playerProfile = {
  name: 'Alice',
  level: 10,
  achievements: [
    {
      title: 'Fast Learner',
      emoji: '?'
    },
    {
      title: 'Treasure Hunter',
      emoji: '?'
    }
  ]
};

function deepCopy(obj) {
  return JSON.parse(JSON.stringify(obj));
}

const clonedProfile = deepCopy(playerProfile);

console.log(clonedProfile);
// 输出与playerProfile相同

// 修改克隆的配置文件而不影响原始配置文件
clonedProfile.achievements.push({ title: 'Marathon Runner', emoji: '?' });
console.log(playerProfile.achievements.length); // 输出:2
console.log(clonedProfile.achievements.length); // 输出:3</code>
Inconvénients d'une copie profonde

Bien que la réplication profonde offre de grands avantages pour la précision des données, il est recommandé d'évaluer si une réplication profonde est requise pour chaque cas d'utilisation spécifique. Dans certains cas, la copie peu profonde ou d'autres techniques de gestion des références d'objets peuvent être plus appropriées, offrant ainsi de meilleures performances et réduisant la complexité.

  1. Impact des performances: la réplication profonde peut être coûteuse en calcul, en particulier lorsqu'il s'agit d'objets grands ou complexes. Étant donné que le processus de réplication profond itère sur toutes les propriétés imbriquées, il peut prendre beaucoup de temps pour affecter négativement les performances de votre application.
  2. Consommation de mémoire: la création de résultats de copie profonde dans toute la hiérarchie des objets, y compris tous les objets imbriqués. Cela peut entraîner une utilisation accrue de la mémoire, ce qui peut devenir un problème dans des environnements à limite de mémoire ou lors du traitement de grands ensembles de données.
  3. Référence ronde: la copie profonde peut causer des problèmes lorsqu'un objet contient une référence circulaire (c'est-à-dire lorsque les propriétés d'un objet se réfèrent à elle-même directement ou indirectement). Les références de boucle peuvent provoquer des boucles infinies ou des erreurs de débordement de pile pendant la copie profonde, et les gérer nécessite une logique supplémentaire pour éviter ces problèmes.
  4. Fonction et gestion spéciale des objets: la copie profonde peut ne pas gérer les fonctions ou les objets avec des caractéristiques spéciales comme prévu (par exemple, Date, RegExp, éléments DOM). Par exemple, lors de la copie profonde d'un objet contenant une fonction, une référence à la fonction peut être copiée, mais la fermeture de la fonction et son contexte lié ne sera pas copiée. De même, les objets avec des fonctionnalités spéciales peuvent perdre leurs propriétés et leurs comportements uniques lorsqu'ils sont profondément reproduits.
  5. Complexité d'implémentation: l'écriture d'une fonction de copie profonde personnalisée peut être compliquée, et des méthodes intégrées comme JSON.parse(JSON.stringify(obj)) ont également certaines limites, telles que ne pas être en mesure de gérer correctement les fonctions, des références circulaires ou des objets spéciaux. Bien qu'il existe des bibliothèques tierces telles que Lodash de _.cloneDeep() qui gèrent la réplication profonde plus efficacement, l'ajout de dépendances externes pour une réplication profonde peut ne pas toujours être idéale.

Conclusion

Merci d'avoir pris le temps de lire cet article. La réplication superficielle et profonde est beaucoup plus complexe que tout débutant ne pourrait le penser. Bien qu'il existe de nombreux pièges dans chaque approche, prendre le temps d'examiner et considérer ces options garantira que votre application et vos données conservent à quoi vous voulez ressembler.

FAQ sur la réplication peu profonde et profonde en JavaScript (FAQ)

Quelle est la principale différence entre la réplication superficielle et profonde en JavaScript?

La principale différence entre la réplication peu profonde et la réplication profonde est la façon dont ils gèrent les propriétés en tant qu'objets. En copie peu profonde, l'objet copié partage la même référence à l'objet imbriqué que l'objet d'origine. Cela signifie que les changements aux objets imbriqués seront reflétés dans l'objet d'origine et l'objet Copie. La réplication profonde, en revanche, crée de nouvelles instances d'objets imbriqués, ce qui signifie que les changements d'objets imbriqués dans l'objet répliqué n'affectent pas l'objet d'origine.

Comment fonctionne l'opérateur d'expansion en copie superficielle?

L'opérateur d'extension (…) en JavaScript est généralement utilisé pour la copie peu profonde. Il copie toutes les propriétés énumérables d'un objet à un autre. Cependant, il copie uniquement les attributs et références de premier niveau à des objets imbriqués. Par conséquent, les modifications des objets imbriqués affecteront l'objet d'origine et l'objet copié.

Puis-je utiliser la méthode JSON pour la copie en profondeur?

Oui, vous pouvez utiliser la méthode JSON pour effectuer une copie profonde dans JavaScript. Une combinaison de méthodes JSON.stringify() et JSON.parse() crée une copie profonde d'un objet. JSON.stringify() convertit l'objet en une chaîne, JSON.parse() analyse la chaîne vers le nouvel objet. Cependant, cette méthode a certaines limites car elle ne copie pas la méthode et ne convient pas aux objets JavaScript spéciaux tels que Date, RegExp, Map, Set, etc.

Quelles sont les limites de la réplication peu profonde?

La copie peu profonde reproduit uniquement les attributs et références de premier niveau aux objets imbriqués. Par conséquent, si l'objet d'origine contient des objets imbriqués, les modifications de ces objets imbriqués affecteront l'objet d'origine et l'objet copié. Cela peut conduire à des résultats et des erreurs inattendus dans le code.

Object.assign() Comment fonctionne la méthode en copie superficielle?

La méthode

Object.assign() est utilisée pour copier les valeurs de toutes les propriétés énumérées d'un ou plusieurs objets source à l'objet cible. Il renvoie l'objet cible. Cependant, il effectue une copie peu profonde, ce qui signifie qu'il copie uniquement les propriétés et références de premier niveau à des objets imbriqués.

Quelle est la meilleure façon de copier profondément des objets en JavaScript?

La meilleure façon de copier en profondeur des objets en JavaScript dépend des exigences spécifiques du code. Si votre objet ne contient pas de méthodes ou d'objets JavaScript spéciaux, vous pouvez utiliser une combinaison de méthodes JSON.stringify() et JSON.parse(). Pour des objets plus complexes, vous voudrez peut-être utiliser des bibliothèques comme Lodash, qui offrent des fonctions de clonage profondes.

Puis-je utiliser l'opérateur d'extension pour une copie profonde?

Non, l'opérateur d'extension en JavaScript effectue uniquement une copie peu profonde. Il copie l'attribut de premier niveau et fait référence aux objets imbriqués. Pour effectuer une réplication profonde, vous devez utiliser une autre méthode ou bibliothèque.

Quel est l'impact des performances de la réplication profonde?

La réplication profonde peut consommer plus de ressources que la réplication peu profonde, en particulier pour les grands objets. En effet, la copie profonde crée de nouvelles instances pour tous les objets imbriqués, ce qui peut prendre plus de mémoire et de puissance de traitement.

Comment gérer les références circulaires en reproduction profonde?

Des méthodes de copie profonde telles que

JSON.stringify() et JSON.parse() ne gèrent pas les références circulaires et lanceront une erreur. Une référence circulaire se produit lorsque les propriétés d'un objet se réfèrent à l'objet lui-même. Pour gérer les références circulaires, vous devez utiliser une bibliothèque qui le prend en charge, comme Lodash.

Pourquoi devrais-je me soucier de la différence entre une copie superficielle et une copie profonde?

Comprendre la différence entre la réplication superficielle et profonde est essentielle pour gérer les données en JavaScript. Cela affecte la façon dont vos objets interagissent les uns avec les autres. Si vous ne faites pas attention, la copie peu profonde peut conduire à des résultats et des erreurs inattendus, car les modifications des objets imbriqués affectent les objets d'origine et copiés. Deep Copy, en revanche, garantit que votre objet de copie est complètement indépendant de l'objet d'origine.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn