Heim  >  Artikel  >  Web-Frontend  >  Grundlegende JavaScript-Tipps (Bild- und Text-Tutorials, ausführliche Antworten für Sie)

Grundlegende JavaScript-Tipps (Bild- und Text-Tutorials, ausführliche Antworten für Sie)

亚连
亚连Original
2018-05-18 16:50:581227Durchsuche

Vorwort

Wenn es um tiefes und flaches Kopieren geht, müssen wir zuerst die Datentypen von JavaScript erwähnen. Der vorherige Artikel „Grundlagen von JavaScript – Datentypen“ hat es sehr deutlich gemacht hier gibt es viel zu sagen.

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

Beim Kopieren von Basisdatentypen gibt es keinen Unterschied zwischen dunklen und flachen Kopien. Was wir als dunkle und flache Kopien bezeichnen, bezieht sich auf 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 Möglichkeit, den =-Zuweisungsoperator zum Implementieren einer flachen Kopie zu verwenden. Es ist deutlich zu erkennen, dass sich auch originArray und originObj ändern, wenn sich cloneArray und cloneObj ändern.

Deep Copy

Deep Copy ist eine vollständige Kopie des Ziels. Im Gegensatz zu einer flachen Kopie, bei der nur eine Ebene von Referenzen kopiert wird, wird sogar der Wert kopiert.

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

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

Verwenden Sie Parse und Stringify im JSON-Objekt.

Verwenden Sie Rekursion, um jede Ebene neu zu erstellen Objekt und Wert zuweisen

JSON.stringify/parse-Methode

Schauen wir uns zunächst diese beiden Methoden an:

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

JSON.stringify konvertiert einen JavaScript-Wert in einen JSON-String.

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

JSON.parse dient dazu, einen JSON-String in einen JavaScript-Wert oder ein JavaScript-Objekt umzuwandeln .

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

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

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

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

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

Es wurde festgestellt, dass in cloneObj einige Attribute fehlen. . . Warum?

Grund auf MDN gefunden:

Wenn bei der Konvertierung eine undefinierte Funktion oder ein Symbol angetroffen wird, wird es entweder weggelassen (wenn es in einem Objekt gefunden wird) oder auf null zensiert (wenn es wird in einem Array gefunden). JSON.stringify kann auch einfach undefiniert zurückgeben, wenn „reine“ Werte wie JSON.stringify(function(){}) oder JSON.stringify(undefined) übergeben werden.

undefiniert, Funktion, Symbol werden während des Konvertierungsvorgangs ignoriert. . .

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

Rekursive Methode

Die Idee der Rekursion ist sehr einfach. Sie besteht darin, für jede Datenschicht einmal ein Objekt zu erstellen -> einfacher und grober Code

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

Versuchen wir es:

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'}};
可以。那再试试带有函数的:
const originObj = {
 name:'axuebin',
 sayHello:function(){
 console.log('Hello World');
 }
}
console.log(originObj); // {name: "axuebin", sayHello: ƒ}
const cloneObj = deepClone(originObj);
console.log(cloneObj); // {name: "axuebin", sayHello: ƒ}

funktioniert auch. Erledigt.

Glaubst du, das ist das Ende? ? Natürlich nicht.

Methoden in JavaScript kopieren

Wir wissen, dass Arrays in JavaScript zwei Methoden haben, concat und Slice, die das ursprüngliche Array kopieren können , sondern gibt stattdessen ein neues, geändertes Array zurück.

Gleichzeitig führte ES6 die Methode Object.assgn und den Spread-Operator ein, um auch Objekte zu kopieren.

Sind sie flache Kopien oder tiefe Kopien?

concat

Die Methode concat() wird verwendet, um zwei oder mehr Arrays zusammenzuführen. Diese Methode ändert nicht die vorhandenen Arrays, sondern gibt stattdessen ein neues Array zurück.

Die Die Methode kann zwei oder mehr Arrays verketten, verändert jedoch nicht das vorhandene Array, sondern gibt ein neues Array zurück.

Sieht so aus, als würde das eine tiefe Kopie bedeuten. Versuchen wir es:

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

Es sieht aus wie eine tiefe Kopie.

Betrachten wir ein Problem: Was passiert, wenn dieses Objekt mehrschichtig ist?

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 enthält Array [1,2,3] und Objekt {a:1}. Wenn wir das Array und das Objekt direkt ändern, hat dies keine Auswirkungen auf originArray, aber wir ändern das Array [1,2, 3] Oder Objekt {a:1}, es wurde festgestellt, dass sich auch originArray geändert hat.

Fazit: concat erstellt nur eine tiefe Kopie der ersten Ebene des Arrays.

slice

Die Methode „slice()“ gibt eine flache Kopie eines Teils eines Arrays in ein neues Array-Objekt zurück, das vom Anfang bis zum Ende ausgewählt wird (das Ende wird nicht berücksichtigt). geändert.

Die Erklärung besagt direkt, dass es sich um eine oberflächliche Kopie handelt~

Aber das ist nicht der Fall!

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

Ähnlich versuchen wir es mit einem mehrstufigen Array.

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

Tatsächlich ist das Ergebnis das gleiche wie bei concat.

Schlussfolgerung: Slice erstellt nur eine tiefe Kopie der ersten Ebene des Arrays.

Object.assign()

Die Methode Object.assign() wird verwendet, um die Werte aller aufzählbaren eigenen Eigenschaften von einem oder mehreren Quellobjekten auf ein Zielobjekt zu kopieren Geben Sie das Zielobjekt zurück.

Kopieren, kopieren, kopieren.

Ist es eine flache Kopie oder eine tiefe Kopie?

Probieren Sie es selbst aus. .

结论: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 中的一个对象被修改了。。。说好的深拷贝呢?不是引用地址都不一样了吗?

原来是这样:

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

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

总结

赋值运算符 = 实现的是浅拷贝,只拷贝对象的引用值;

JavaScript 中数组和对象自带的拷贝方法都是“首层浅拷贝”;

JSON.stringify 实现的是深拷贝,但是对目标对象有要求;

若想真正意义上的深拷贝,请递归。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

用p5.js制作烟花特效的示例代码_javascript技巧

JS+PHP往类动态添加方法

怎样用JS检测电脑配置

Das obige ist der detaillierte Inhalt vonGrundlegende JavaScript-Tipps (Bild- und Text-Tutorials, ausführliche Antworten für Sie). 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