Maison > interface Web > js tutoriel > Une compréhension approfondie de la copie superficielle et de la copie profonde en JavaScript

Une compréhension approfondie de la copie superficielle et de la copie profonde en JavaScript

零到壹度
Libérer: 2018-04-21 15:32:17
original
1154 Les gens l'ont consulté

Le contenu de cet article porte sur une compréhension approfondie de la copie superficielle et de la copie profonde en JavaScript. Il a une certaine valeur de référence. Maintenant, je le partage avec vous. Les amis dans le besoin peuvent s'y référer<.>

Il existe des types de base en JS comme

, Number, String et les objets sont comme ceci { nom : 'Larry', compétence : 'Node.js' }, les objets et les types de base sont le plus grand La différence réside dans la manière dont ils transmettent les valeurs. Le type de base de Boolean,

est passé par valeur, comme ceci : Lors de la modification de

, il ne sera pas changé en ab

var a = 25;
var b = a;
b = 18;
console.log(a);//25
console.log(b);//18
Copier après la connexion
Mais l'objet est différent. l'objet est passé par valeur. Passer par valeur :

var obj1 = { a: 10, b: 20, c: 30 };
var obj2 = obj1;
obj2.b = 100;
console.log(obj1);
// { a: 10, b: 100, c: 30 } <-- b 被改到了
console.log(obj2);
// { a: 10, b: 100, c: 30 }
Copier après la connexion
Copiez une copie de

et appelez-la obj1, puis remplacez obj2, par obj2.b mais remplacez-la accidentellement par 100,. car il s’agit fondamentalement du même objet. C’est ce qu’on appelle une copie superficielle. obj1.b,

Pour éviter de telles erreurs, écrivez comme ceci :

var obj1 = { a: 10, b: 20, c: 30 };
var obj2 = { a: obj1.a, b: obj1.b, c: obj1.c };
obj2.b = 100;
console.log(obj1);
// { a: 10, b: 20, c: 30 } <-- b 沒被改到
console.log(obj2);
// { a: 10, b: 100, c: 30 }
Copier après la connexion


Ceci est une copie complète et ne changera pas à l'original

obj1。

Copie superficielle VS copie profonde

La copie superficielle copie uniquement le pointeur vers un objet sans copier l'objet lui-même, l'ancien et le nouveau. les objets partagent toujours la même mémoire. Cependant, la copie complète créera un objet identique. Le nouvel objet ne partage pas la mémoire avec l'objet d'origine et les modifications apportées au nouvel objet ne modifieront pas l'objet d'origine.

La mise en œuvre de la copie superficielle

consiste simplement à copier

1 Copiez simplement la déclaration

  <script type="text/javascript">
    function simpleClone(initalObj) {    
      var obj = {};    
      for ( var i in initalObj) {
        obj[i] = initalObj[i];
      }    
      return obj;
    }    var obj = {
      a: "hello",
      b:{
          a: "world",
          b: 21
        },
      c:["Bob", "Tom", "Jenny"],
      d:function() {
          alert("hello world");
        }
    }    var cloneObj = simpleClone(obj); 
    console.log(cloneObj.b); 
    console.log(cloneObj.c);
    console.log(cloneObj.d);

    cloneObj.b.a = "changed";
    cloneObj.c = [1, 2, 3];
    cloneObj.d = function() { alert("changed"); };
    console.log(obj.b);
    console.log(obj.c);
    console.log(obj.d);  </script>
Copier après la connexion

.

Le résultat est :

2. Object.assign()

Oui Nouvelles fonctions. en ES6. La méthode Object.assign()<code>Object.assign peut copier n'importe quel nombre de propriétés énumérables de l'objet source vers l'objet cible, puis renvoyer l'objet cible. Mais <code>Object.assign() effectue une copie superficielle. Ce qui est copié est la référence aux attributs de l'objet, pas l'objet lui-même. <code>Object.assign()

Object.assign(target, ...sources)
Copier après la connexion
Paramètres :

target : objet cible.

sources : n'importe quel nombre d'objets sources.
Valeur de retour :
L'objet cible sera renvoyé.

var obj = { a: {a: "hello", b: 21} };
var initalObj = Object.assign({}, obj);

initalObj.a.a = "changed";
console.log(obj.a.a); // "changed"
Copier après la connexion
Compatibilité :

Remarque :

Object.assign()可以处理一层的深度拷贝,如下:
Copier après la connexion
var obj1 = { a: 10, b: 20, c: 30 };
var obj2 = Object.assign({}, obj1);
obj2.b = 100;
console.log(obj1);
// { a: 10, b: 20, c: 30 } <-- 沒被改到
console.log(obj2);
// { a: 10, b: 100, c: 30 }
Copier après la connexion


Comment implémenter la copie profonde

Si vous souhaitez copier complètement sans modifier l'objet d'origine, vous devez utiliser Deep Copy. Ici, nous présenterons plusieurs méthodes de Deep Copy.

1. Copie manuelle

Copier les propriétés d'un objet dans les propriétés d'un autre objet

var obj1 = { a: 10, b: 20, c: 30 };
var obj2 = { a: obj1.a, b: obj1.b, c: obj1.c };
obj2.b = 100;
console.log(obj1);
// { a: 10, b: 20, c: 30 } <-- 沒被改到
console.log(obj2);
// { a: 10, b: 100, c: 30 }
Copier après la connexion
Mais c'est très gênant, vous besoin d'un One se copie ; et cette nature ne peut pas être considérée comme Deep Copy, car il peut aussi y avoir des objets à l'intérieur de l'objet, comme dans la situation suivante :

var obj1 = { body: { a: 10 } };
var obj2 = { body: obj1.body };
obj2.body.a = 20;
console.log(obj1);
// { body: { a: 20 } } <-- 被改到了
console.log(obj2);
// { body: { a: 20 } }
console.log(obj1 === obj2);
// false
console.log(obj1.body === obj2.body);
// true
Copier après la connexion
Bien que

et obj2 <code>obj1 sont des objets différents, mais ils partageront le même obj1.body<code>obj2, <code>obj1.body donc lorsque vous modifierez obj2.body.a<code>,, l'ancien sera également être modifié. obj2.body.a

2. Si l'objet n'a qu'un seul calque, vous pouvez utiliser ce qui précède : Objet<strong>.<span class="token function">attribuer () function<code class=" language-js">Object<span class="token punctuation">.<span class="token function">assign()函数</span></span>

<code>Object.assign({}, obj1)obj1<code>Object.assign({}, obj1)<code>obj2 signifie d'abord créer un objet vide {}, et puis attribuez obj1 Copiez tous les attributs dans obj2.b, donc obj2<code>obj1。 aura la même apparence que
La modification de
à ce moment n'affectera pas <code>Object.assign

. parce que Object .assign<p> a le même effet que notre copie manuelle, il ne peut donc gérer que des objets avec une seule couche de profondeur, et il n'y a aucun moyen d'obtenir une véritable copie profonde. Cependant, vous pouvez envisager de l'utiliser s'il n'y a qu'un seul calque d'objets à copier. <strong><span class="token punctuation"></span></strong></p>3. Convertissez <p> en JSON, puis inversez <span class="token punctuation"><code>JSON.stringifyJSON.parseUtilisez JSON.stringify</p> pour convertir l'objet Convertissez-le en chaîne, puis utilisez <code>JSON.parse<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">var obj1 = { body: { a: 10 } }; var obj2 = JSON.parse(JSON.stringify(obj1)); obj2.body.a = 20; console.log(obj1); // { body: { a: 10 } } &lt;-- 沒被改到 console.log(obj2); // { body: { a: 20 } } console.log(obj1 === obj2); // false console.log(obj1.body === obj2.body); // false</pre><div class="contentsignin">Copier après la connexion</div></div> pour convertir la chaîne en un nouvel objet. <p><span style="line-height: 1.5;"></span><br/>C'est du vrai Deep Copy, </p>Cette méthode est simple et facile à utiliser. <p></p><p><code>Number, String, Boolean, Array, 扁平对象Mais cette méthode présente également de nombreux inconvénients, par exemple, elle supprimera le constructeur de l'objet. C'est-à-dire qu'après une copie profonde, quel que soit le constructeur d'origine de l'objet, il deviendra Objet après une copie profonde.

Les seuls objets que cette méthode peut gérer correctement sont les Number, String, Boolean, Array et les objets plats<code>JSON, c'est-à-dire les structures de données qui peuvent être directement représentées par json. Les objets RegExp ne peuvent pas être copiés en profondeur de cette manière. functionJSON。En d'autres termes, seuls les objets pouvant être convertis au format JSON</p> peuvent être utilisés de cette manière. Par exemple, <code>function<🎜> ne peut pas être converti en <code>JSON. . <🎜><🎜><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">var obj1 = { fun: function(){ console.log(123) } }; var obj2 = JSON.parse(JSON.stringify(obj1)); console.log(typeof obj1.fun); // &amp;#39;function&amp;#39; console.log(typeof obj2.fun); // &amp;#39;undefined&amp;#39; &lt;-- 没复制</pre><div class="contentsignin">Copier après la connexion</div></div><p>要复制的<code>function会直接消失,所以这个方法只能用在单纯只有数据的对象。

4、递归拷贝

function deepClone(initalObj, finalObj) {    
  var obj = finalObj || {};    
  for (var i in initalObj) {        
    if (typeof initalObj[i] === &#39;object&#39;) {
      obj[i] = (initalObj[i].constructor === Array) ? [] : {};            
      arguments.callee(initalObj[i], obj[i]);
    } else {
      obj[i] = initalObj[i];
    }
  }    
  return obj;
}var str = {};var obj = { a: {a: "hello", b: 21} };
deepClone(obj, str);
console.log(str.a);
Copier après la connexion

上述代码确实可以实现深拷贝。但是当遇到两个互相引用的对象,会出现死循环的情况。

为了避免相互引用的对象导致死循环的情况,则应该在遍历的时候判断是否相互引用对象,如果是则退出循环。

改进版代码如下:

function deepClone(initalObj, finalObj) {    
  var obj = finalObj || {};    
  for (var i in initalObj) {        
    var prop = initalObj[i];        // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况
    if(prop === obj) {            
      continue;
    }        
    if (typeof prop === &#39;object&#39;) {
      obj[i] = (prop.constructor === Array) ? [] : {};            
      arguments.callee(prop, obj[i]);
    } else {
      obj[i] = prop;
    }
  }    
  return obj;
}var str = {};var obj = { a: {a: "hello", b: 21} };
deepClone(obj, str);
console.log(str.a);
Copier après la connexion


5、使用Object.create()方法

直接使用var newObj = Object.create(oldObj),可以达到深拷贝的效果。

function deepClone(initalObj, finalObj) {    
  var obj = finalObj || {};    
  for (var i in initalObj) {        
    var prop = initalObj[i];        // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况
    if(prop === obj) {            
      continue;
    }        
    if (typeof prop === &#39;object&#39;) {
      obj[i] = (prop.constructor === Array) ? [] : Object.create(prop);
    } else {
      obj[i] = prop;
    }
  }    
  return obj;
}
Copier après la connexion


6、jquery

jquery 有提供一个$.extend可以用来做 Deep Copy。

var $ = require(&#39;jquery&#39;);var obj1 = {
    a: 1,
    b: { f: { g: 1 } },
    c: [1, 2, 3]
};var obj2 = $.extend(true, {}, obj1);
console.log(obj1.b.f === obj2.b.f);// false
Copier après la connexion


7、lodash

另外一个很热门的函数库lodash,也有提供_.cloneDeep用来做 Deep Copy。

var _ = require(&#39;lodash&#39;);var obj1 = {
    a: 1,
    b: { f: { g: 1 } },
    c: [1, 2, 3]
};var obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);// false
Copier après la connexion

这个性能还不错,使用起来也很简单。

 

参考:

JavaScript 中对象的深拷贝

关于 JS 中的浅拷贝和深拷贝

iOS 深拷贝两种实现

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!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
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
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal