Heim  >  Artikel  >  Web-Frontend  >  Detaillierte Erläuterung der Schritte zur Verwendung von tiefem und flachem Kopieren von JS

Detaillierte Erläuterung der Schritte zur Verwendung von tiefem und flachem Kopieren von JS

php中世界最好的语言
php中世界最好的语言Original
2018-04-12 10:52:341404Durchsuche

Dieses Mal erkläre ich Ihnen ausführlich die Schritte zur Verwendung der tiefen und flachen Kopie von JS. Was sind die Vorsichtsmaßnahmen bei der Verwendung der tiefen und flachen Kopie von JS? , lass uns einen Blick darauf werfen.

Apropos tiefes und flaches Kopieren: Wir müssen zuerst den Datentyp von JavaScript erwähnen Es ist klar, viel mehr werde ich hier nicht sagen.

Was Sie wissen müssen, ist eines: JavaScript-Datentypen werden in Basisdatentypen und Referenzdatentypen unterteilt.

Bei der Kopie von Basisdatentypen gibt es keinen Unterschied zwischen dunklen und flachen Kopien. Was wir als dunkle und flache Kopien bezeichnen, sind alle für Referenzdatentypen.

Flache Kopie

Flache Kopie bedeutet, dass nur die Referenz kopiert wird, der tatsächliche Wert jedoch nicht.

const originArray = [1,2,3,4,5];
const originObj = {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};
const cloneArray = originArray;
const cloneObj = originObj;
console.log(cloneArray); // [1,2,3,4,5]
console.log(originObj); // {a:'a',b:'b',c:Array[3],d:{dd:'dd'}}
cloneArray.push(6);
cloneObj.a = {aa:'aa'};
console.log(cloneArray); // [1,2,3,4,5,6]
console.log(originArray); // [1,2,3,4,5,6]
console.log(cloneObj); // {a:{aa:'aa'},b:'b',c:Array[3],d:{dd:'dd'}}
console.log(originArray); // {a:{aa:'aa'},b:'b',c:Array[3],d:{dd:'dd'}}

Der obige Code ist die einfachste Verwendung des =-Zuweisungsoperators , um eine flache Kopie zu implementieren. Es ist deutlich zu erkennen, dass sich und cloneArray ändern, wenn sich cloneObj und originArray ändern Dinge haben sich geändert. originObj

Deep Copy

Eine tiefe Kopie ist eine vollständige Kopie des Ziels. Im Gegensatz zu einer flachen Kopie, die nur eine Ebene von Referenzen kopiert, werden sogar die Werte kopiert.

Solange eine tiefe Kopie erstellt wird, werden sie niemals miteinander interagieren und niemand wird andere beeinflussen.

Derzeit gibt es nicht viele Möglichkeiten, Deep Copy zu implementieren. Es gibt hauptsächlich zwei Methoden:

  1. Verwenden Sie Parse und Stringify im JSON-Objekt

  2. Verwenden Sie Rekursion, um jede Ebene zu erreichen, um das Objekt neu zu erstellen
  3. und weisen Sie den Wert

  4. JSON.stringify/parse-Methode

Schauen wir uns zunächst diese beiden Methoden an:

Die Methode JSON.stringify() konvertiert einen JavaScript-Wert in einen JSON-String

konvertiert einen JavaScript-Wert in einen JSON-String.

JSON.stringify Die JSON.parse()-Methode analysiert einen JSON-String und erstellt den durch den String beschriebenen JavaScript-Wert oder das JavaScript-Objekt

konvertiert einen JSON-String in einen JavaScript-Wert oder ein JavaScript-Objekt.

Es ist leicht zu verstehen, es handelt sich um die Konvertierung zwischen JavaScript-Werten und JSON-Strings.

Kann es eine tiefe Kopie erreichen? Lass es uns versuchen.

JSON.parse

Es ist in der Tat eine tiefe Kopie und sehr praktisch. Diese Methode kann jedoch nur auf einige einfache Situationen angewendet werden. Beispielsweise gilt das folgende Objekt nicht:

Es wurde festgestellt, dass einige Attribute in

fehlen. . . Warum?
const originArray = [1,2,3,4,5];
const cloneArray = JSON.parse(JSON.stringify(originArray));
console.log(cloneArray === originArray); // false
const originObj = {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};
const cloneObj = JSON.parse(JSON.stringify(originObj));
console.log(cloneObj === originObj); // false
cloneObj.a = 'aa';
cloneObj.c = [1,1,1];
cloneObj.d.dd = 'doubled';
console.log(cloneObj); // {a:'aa',b:'b',c:[1,1,1],d:{dd:'doubled'}};
console.log(originObj); // {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};

Den Grund auf MDN gefunden:

const originObj = {
 name:'axuebin',
 sayHello:function(){
 console.log('Hello World');
 }
}
console.log(originObj); // {name: "axuebin", sayHello: ƒ}
const cloneObj = JSON.parse(JSON.stringify(originObj));
console.log(cloneObj); // {name: "axuebin"}

Wenn undefiniert, wird währenddessen eine Funktion oder ein Symbol angetroffen Bei der Konvertierung wird es entweder weggelassen (wenn es in einem Objekt gefunden wird) oder auf null zensiert (wenn es in einem Array gefunden wird, kann JSON.stringify auch). Geben Sie einfach undefiniert zurück, wenn Sie „reine“ Werte wie übergeben JSON.stringify(function(){}) oder JSON.stringify(undefiniert). cloneObj ,

,

werden bei der Konvertierung ignoriert. . .

Das heißt, wenn das Objekt eine Funktion enthält (sehr häufig), können Sie diese Methode nicht zum Durchführen einer Tiefenkopie verwenden.

Rekursive Methode

undefinedfunction Die Idee der Rekursion ist sehr einfach. Sie besteht darin, die Operation zum Erstellen eines Objekts -> Objektzuweisung für jede Datenschicht zu implementieren. Der Code ist einfach und grob: symbol

Versuchen wir es:

Dürfen. Dann probieren Sie es mit den Funktionen:

Das ist auch ok. Erledigt.

function deepClone(source){
 const targetObj = source.constructor === Array ? [] : {}; // 判断复制的目标是数组还是对象
 for(let keys in source){ // 遍历目标
 if(source.hasOwnProperty(keys)){
 if(source[keys] && typeof source[keys] === 'object'){ // 如果值是对象,就递归一下
 targetObj[keys] = source[keys].constructor === Array ? [] : {};
 targetObj[keys] = deepClone(source[keys]);
 }else{ // 如果不是,就直接赋值
 targetObj[keys] = source[keys];
 }
 } 
 }
 return targetObj;
}
Glaubst du, das ist das Ende? ? Natürlich nicht.

const originObj = {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};
const cloneObj = deepClone(originObj);
console.log(cloneObj === originObj); // false
cloneObj.a = 'aa';
cloneObj.c = [1,1,1];
cloneObj.d.dd = 'doubled';
console.log(cloneObj); // {a:'aa',b:'b',c:[1,1,1],d:{dd:'doubled'}};
console.log(originObj); // {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};
Methode in JavaScript kopieren

我们知道在 JavaScript 中,数组有两个方法 concat 和 slice 是可以实现对原数组的拷贝的,这两个方法都不会修改原数组,而是返回一个修改后的新数组。

同时,ES6 中 引入了 Object.assgn 方法和 ... 展开运算符也能实现对对象的拷贝。

那它们是浅拷贝还是深拷贝呢?

concat

The concat() method is used to merge two or more arrays. This method does not change the existing arrays, but instead returns a new array.

该方法可以连接两个或者更多的数组,但是它不会修改已存在的数组,而是返回一个新数组。

看着这意思,很像是深拷贝啊,我们来试试:

const originArray = [1,2,3,4,5];
const cloneArray = originArray.concat();
console.log(cloneArray === originArray); // false
cloneArray.push(6); // [1,2,3,4,5,6]
console.log(originArray); [1,2,3,4,5];

看上去是深拷贝的。

我们来考虑一个问题,如果这个对象是多层的,会怎样。

const originArray = [1,[1,2,3],{a:1}];
const cloneArray = originArray.concat();
console.log(cloneArray === originArray); // false
cloneArray[1].push(4);
cloneArray[2].a = 2; 
console.log(originArray); // [1,[1,2,3,4],{a:2}]

originArray 中含有数组 [1,2,3] 和对象 {a:1},如果我们直接修改数组和对象,不会影响 originArray,但是我们修改数组 [1,2,3] 或对象 {a:1} 时,发现 originArray 也发生了变化。

结论:concat 只是对数组的第一层进行深拷贝。

slice

The slice() method returns a shallow copy of a portion of an array into a new array object selected from begin to end (end not included). The original array will not be modified.

解释中都直接写道是 a shallow copy 了 ~

但是,并不是!

const originArray = [1,2,3,4,5];
const cloneArray = originArray.slice();
console.log(cloneArray === originArray); // false
cloneArray.push(6); // [1,2,3,4,5,6]
console.log(originArray); [1,2,3,4,5];

同样地,我们试试多层的数组。

const originArray = [1,[1,2,3],{a:1}];
const cloneArray = originArray.slice();
console.log(cloneArray === originArray); // false
cloneArray[1].push(4);
cloneArray[2].a = 2; 
console.log(originArray); // [1,[1,2,3,4],{a:2}]

果然,结果和 concat 是一样的。

结论:slice 只是对数组的第一层进行深拷贝。

Object.assign()

The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object.

复制复制复制。

那到底是浅拷贝还是深拷贝呢?

自己试试吧。。

结论:Object.assign() 拷贝的是属性值。假如源对象的属性值是一个指向对象的引用,它也只拷贝那个引用值。

... 展开运算符

const originArray = [1,2,3,4,5,[6,7,8]];
const originObj = {a:1,b:{bb:1}};
const cloneArray = [...originArray];
cloneArray[0] = 0;
cloneArray[5].push(9);
console.log(originArray); // [1,2,3,4,5,[6,7,8,9]]
const cloneObj = {...originObj};
cloneObj.a = 2;
cloneObj.b.bb = 2;
console.log(originObj); // {a:1,b:{bb:2}}

结论:... 实现的是对象第一层的深拷贝。后面的只是拷贝的引用值。

首层浅拷贝

我们知道了,会有一种情况,就是对目标对象的第一层进行深拷贝,然后后面的是浅拷贝,可以称作“首层浅拷贝”。

我们可以自己实现一个这样的函数:

function shallowClone(source) {
 const targetObj = source.constructor === Array ? [] : {}; // 判断复制的目标是数组还是对象
 for (let keys in source) { // 遍历目标
 if (source.hasOwnProperty(keys)) {
 targetObj[keys] = source[keys];
 }
 }
 return targetObj;
}

我们来测试一下:

const originObj = {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};
const cloneObj = shallowClone(originObj);
console.log(cloneObj === originObj); // false
cloneObj.a='aa';
cloneObj.c=[1,1,1];
cloneObj.d.dd='surprise';

经过上面的修改,cloneObj 不用说,肯定是 {a:'aa',b:'b',c:[1,1,1],d:{dd:'surprise'}} 了,那 originObj 呢?刚刚我们验证了 cloneObj === originObj 是 false,说明这两个对象引用地址不同啊,那应该就是修改了 cloneObj 并不影响 originObj。

console.log(cloneObj); // {a:'aa',b:'b',c:[1,1,1],d:{dd:'surprise'}}
console.log(originObj); // {a:'a',b:'b',c:[1,2,3],d:{dd:'surprise'}}

What happend?

originObj 中关于 a、c都没被影响,但是 d 中的一个对象被修改了。。。说好的深拷贝呢?不是引用地址都不一样了吗?

原来是这样:

  1. 从 shallowClone 的代码中我们可以看出,我们只对第一层的目标进行了 深拷贝 ,而第二层开始的目标我们是直接利用 = 赋值操作符进行拷贝的。

  2. so,第二层后的目标都只是复制了一个引用,也就是浅拷贝。

总结

  1. Zuweisungsoperator = implementiert eine flache Kopie, die nur den Referenzwert des Objekts kopiert;

  2. Die Kopiermethoden von Arrays und Objekten in JavaScript sind alle „flache Kopien der ersten Ebene“. " ;

  3. JSON.stringify implementiert Deep Copy, stellt aber Anforderungen an das Zielobjekt;

  4. Wenn Sie eine echte Deep Copy wünschen, Bitte rekursiv.

Ich glaube, dass Sie die Methode beherrschen, nachdem Sie den Fall in diesem Artikel gelesen haben. Weitere spannende Informationen finden Sie in anderen verwandten Artikeln auf der chinesischen PHP-Website!

Empfohlene Lektüre:

Detaillierte Erläuterung der HTTP-Anfrage und der Ladeanzeigenutzung von Vue2.0

Prozess- und child_process-Module des Knotens Ausführliche Nutzungserklärung

Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung der Schritte zur Verwendung von tiefem und flachem Kopieren von JS. 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