Heim  >  Artikel  >  Web-Frontend  >  Ein tiefgreifendes Verständnis von Shallow Copy und Deep Copy in JavaScript

Ein tiefgreifendes Verständnis von Shallow Copy und Deep Copy in JavaScript

零到壹度
零到壹度Original
2018-04-21 15:32:171085Durchsuche

Der Inhalt dieses Artikels befasst sich mit einem tiefgreifenden Verständnis von Shallow Copy und Deep Copy. Jetzt kann ich ihn mit allen teilen, die ihn brauchen.

Es gibt einige Grundtypen in JS wie Number, String, Boolean, und Objekte sind wie folgt: { Name: 'Larry', Skill: 'Node.js' }, Objekte und Grundtypen sind Der größte Unterschied liegt in der Art und Weise, wie sie Werte übergeben. Der Grundtyp von

wird wie folgt als Wert übergeben: Beim Ändern von a wird er nicht in b

var a = 25;
var b = a;
b = 18;
console.log(a);//25
console.log(b);//18

geändert. Das Objekt ist jedoch anders Objekt wird als Wert übergeben:

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 }

Kopieren Sie eine Kopie von obj1 und nennen Sie sie obj2, und ändern Sie dann obj2.b in 100,, ändern Sie es jedoch versehentlich in obj1.b, weil es sich im Grunde um dasselbe Objekt handelt. Dies wird als flache Kopie bezeichnet.

Um solche Fehler zu vermeiden, schreiben Sie wie folgt:

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 }


Dies ist eine tiefe Kopie und wird nicht am Original verändert obj1。

Shallow Copy VS Deep Copy

Shallow Copy kopiert nur den Zeiger auf ein Objekt, ohne das Objekt selbst, das Alte und das Neue zu kopieren Objekte teilen sich immer noch den gleichen Speicher. Durch eine tiefe Kopie wird jedoch ein identisches Objekt erstellt. Das neue Objekt teilt sich den Speicher nicht mit dem Originalobjekt, und Änderungen am neuen Objekt führen nicht zu einer Änderung des Originalobjekts.

Die Implementierung von Shallow Copy

ist einfach das Kopieren

1. Kopieren Sie einfach die Aussage

  <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>


Das Ergebnis ist:

2. Object.assign()

<code>Object.assignJa Neue Funktionen in ES6. Die Methode Object.assign() kann eine beliebige Anzahl der aufzählbaren Eigenschaften des Quellobjekts in das Zielobjekt kopieren und dann das Zielobjekt zurückgeben. Aber <code>Object.assign()<code>Object.assign() führt eine flache Kopie durch und kopiert Verweise auf die Eigenschaften des Objekts, nicht das Objekt selbst.

Object.assign(target, ...sources)

Parameter:

Ziel: Zielobjekt.
Quellen: beliebig viele Quellobjekte.
Rückgabewert: Das Zielobjekt wird zurückgegeben.

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

initalObj.a.a = "changed";
console.log(obj.a.a); // "changed"

Kompatibilität:

Hinweis:

Object.assign()可以处理一层的深度拷贝,如下:
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 }


So implementieren Sie Deep Copy

Wenn Sie das Originalobjekt vollständig kopieren möchten, müssen Sie Deep Copy verwenden. Hier stellen wir verschiedene Deep Copy-Methoden vor.

1. Manuelles Kopieren

Kopieren Sie die Eigenschaften eines Objekts in die Eigenschaften eines anderen Objekts

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 }

Aber das ist sehr mühsam, Sie Ein Man muss sich selbst kopieren; und diese Art kann nicht als Deep Copy betrachtet werden, da es auch Objekte innerhalb des Objekts geben kann, wie zum Beispiel die folgende Situation:

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

Obwohl obj1 und obj2 <code>obj2 sind unterschiedliche Objekte, aber sie haben denselben obj1.body<code>obj1.body, <code>,. Wenn Sie also obj2.body.a<code>obj2.body.a ändern, wird dies auch beim alten der Fall sein geändert werden.

2. Wenn das Objekt nur eine Ebene hat, können Sie Folgendes verwenden: Objekt<code class=" language-js">Object<span class="token punctuation">.<span class="token function">assign()函数</span></span>.zuordnen () Funktion

<code>Object.assign({}, obj1)obj1obj2<code>Object.assign({}, obj1)<code>obj1 bedeutet, zuerst ein leeres Objekt {} zu erstellen, und Weisen Sie dann obj2.bKopieren Sie alle Attribute in obj1。 zu, sodass obj2
genauso aussieht wie
. Das Ändern von <code>Object.assign
hat zu diesem Zeitpunkt keine Auswirkungen auf

weil Object .assign<strong> den gleichen Effekt wie unser manuelles Kopieren hat, es also nur Objekte mit nur einer Tiefenebene verarbeiten kann und es keine Möglichkeit gibt, echtes Deep Copy zu erreichen. Sie können die Verwendung jedoch in Betracht ziehen, wenn nur eine Objektebene kopiert werden soll. <span class="token punctuation"></span></strong>

3. Konvertieren Sie in JSON und dann wieder zurück JSON.stringifyJSON.parse

Verwenden Sie JSON.stringify<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> zu Konvertieren Sie das Objekt. Konvertieren Sie es in eine Zeichenfolge und konvertieren Sie die Zeichenfolge dann mit <code>JSON.parse<p> in ein neues Objekt. <span style="line-height: 1.5;"></span><br></p>Das ist echtes Deep Copy, <p>Diese Methode ist einfach und leicht anzuwenden. </p> <p><code>Number, String, Boolean, Array, 扁平对象

Aber diese Methode hat auch viele Nachteile, zum Beispiel wird der Konstruktor des Objekts verworfen. Das heißt, nach dem tiefen Kopieren wird das Objekt unabhängig vom ursprünglichen Konstruktor des Objekts nach dem tiefen Kopieren zum Objekt.

JSONDie einzigen Objekte, die diese Methode korrekt verarbeiten kann, sind Number-, String-, Boolean-, Array- und flache Objekte<code>function, also jene Datenstrukturen, die direkt durch JSON dargestellt werden können. RegExp-Objekte können auf diese Weise nicht tief kopiert werden. JSON。

Mit anderen Worten: Auf diese Weise können nur Objekte verwendet werden, die in das JSON-Format konvertiert werden können. Beispielsweise kann <code>function nicht in <code>JSON konvertiert werden . <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><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);

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

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

改进版代码如下:

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);


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;
}


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


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

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

 

参考:

JavaScript 中对象的深拷贝

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

iOS 深拷贝两种实现

Das obige ist der detaillierte Inhalt vonEin tiefgreifendes Verständnis von Shallow Copy und Deep Copy in JavaScript. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn