In jeder Programmiersprache gibt es Datentypen, die Programmierer den Subjekten beschreiben, um sie weiter zu bearbeiten und gegebenenfalls zu verarbeiten. JavaScript ist keine Ausnahme, es verfügt über primitive (
Number
,
String
,
Boolean
,
Symbol
usw.) und Referenzdatentypen (
Array
,
Object
,
Function
,
Maps
,
Sets
usw.). Es ist zu beachten, dass primitive Datentypen unveränderlich sind - ihre Werte können nicht geändert, sondern nur mit einem neuen vollständigen Wert überschrieben werden, bei Referenzdatentypen ist das Gegenteil der Fall. Deklarieren Sie beispielsweise Variablen vom Typ
Number
und
Object
:
let num = 5; let obj = { a: 5 };
Wir können die Variable
num
nicht ändern, wir können nur ihren Wert umschreiben, aber wir können die Variable obj ändern:
let num = 10; let obj = { a: 5, b: 6 };
Wie Sie sehen, haben wir im ersten Fall den Wert der Variablen überschrieben und im zweiten Fall das Objekt erweitert. Daraus schließen wir, dass primitive Datentypen nicht erweitert werden können, und mit Referenzdatentypen können wir dies auch mit dem
const
Modifikator tun.
Letzteres kann zum Beispiel mit
Object.freeze(obj)
, aber dieses Thema
Object.freeze(obj)
den Rahmen des Artikels (Links für die neugierige
Object.defineProperty , die
das Objekt vor Änderungen schützen ).
Wie werden Datentypen an Funktionen in JavaScript übergeben? Jeder js-Programmierer wird diese Frage wahrscheinlich leicht beantworten können. Nehmen wir jedoch an, dass primitive Datentypen immer nur nach Wert an eine Funktion übergeben werden und referenzierte Datentypen immer nur nach Referenz. Und hier mit letzterem treten in einigen Situationen Probleme auf.
Schauen wir uns ein Beispiel an:
const arr = [0, 1, 2, 3, 4, 5]; console.log("Array: ", arr);
In diesem Fall haben wir einfach ein Array von Zahlen deklariert und in der Konsole angezeigt. Jetzt übergeben wir es an eine Funktion, die ein neues Array zurückgibt, jedoch mit einem zusätzlichen Wert im zweiten Argument am Ende des neuen Arrays:
const arr = [0, 1, 2, 3, 4, 5]; console.log("Old array: ", arr);
Wie aus den Schlussfolgerungen der Konsole hervorgeht, hat sich nicht nur das neue Array geändert, sondern auch das alte. Dies geschah, weil wir in der Funktion
insertValToArr
nur ein Array einem anderen
const newArr = arr
zugewiesen und daher eine Verknüpfung zu einem vorhandenen Array erstellt haben. Als wir versuchten, ein neues Array zu ändern, bezog es sich auf den Speicherbereich des alten Arrays und änderte ihn grob gesagt. Und da sich beide Arrays auf denselben Speicherbereich beziehen, haben sie denselben Wert. Lassen Sie uns unsere Funktion so ändern, dass sie das alte Array nicht ändern kann:
const arr = [0, 1, 2, 3, 4, 5]; const newArr = insertValToArr(arr, 15); console.log("New array: ", newArr);
Das alte Array hat sich nicht geändert, da wir jedes seiner Elemente erhalten und die Werte des Elements den Elementen des neuen Arrays einzeln zugewiesen haben. Letzterer verfügt nun über einen separaten Speicherbereich. Wenn Sie diesen ändern, wirkt sich dies nicht auf das alte Array aus. Aber all dies sind einfache Beispiele, und in realen Programmen werden höchstwahrscheinlich nicht nur eindimensionale Arrays angetroffen, sondern auch zweidimensionale, seltener dreidimensionale und noch seltener vierdimensionale. Meistens werden sie in Form von assoziativen Arrays (Hash-Tabellen) gefunden. In JavaScript sind dies meist Objekte.
Sehen wir uns die Standardmethoden zum Kopieren von Objekten an, die von JavaScript bereitgestellt werden. Object.assign () wird verwendet, um die Werte aller eigenen aufgezählten Eigenschaften von einem oder mehreren Quellobjekten in das Zielobjekt zu kopieren. Nach dem Kopieren wird das Zielobjekt zurückgegeben. Betrachten Sie es:
const obj = { a: 1 }; const newObj = Object.assign({}, obj); console.log(newObj);
Und wieder das alte Problem, wir verweisen auf denselben Speicherbereich, der zur gleichzeitigen Änderung von zwei Objekten führt - wenn eines geändert wird, wird das andere geändert. Was tun, wenn eine Kopie eines komplexen Objekts (mit mehreren Verzweigungen) angefordert wird und gleichzeitig das Objekt geändert und kein anderes geändert werden soll? Diese Frage zu beantworten ist der Zweck dieses Artikels. Weiterhin werden wir uns überlegen, wie wir unsere eigene Methode zum tiefen Klonen (Kopieren) von Objekten eines beliebigen Zweigs schreiben können. Kommen wir zum Code.
Schritt 1: Deklarieren und initialisieren Sie das Objekt
Z
und geben Sie die Konsole zum Vergleich vor und nach dem Klonen aus:
const Z = { a: 5, b: { g: 8, y: 9, t: { q: 48 } }, x: 47, l: { f: 85, p: { u: 89, m: 7 }, s: 71 }, r: { h: 9, a: 'test', s: 'test2' } }; console.log('Z object before cloning: ', Z);

Schritt 2:
refToZ
dem
refToZ
Objekt das Objekt
Z
zu, um den Unterschied zwischen normaler Zuweisung und tiefem Klonen
refToZ
:
const refToZ = Z;
Schritt 3:
deepClone
Objekt
Z
mit der
deepClone
Funktion Objekt
Y
und fügen Sie
Z
Objekt
Y
eine neue Eigenschaft hinzu. Anschließend zeigen Sie diese beiden Objekte in der Konsole an:
const Y = deepClone(Z); function deepClone(obj) { const clObj = {}; for(const i in obj) { if (obj[i] instanceof Object) { clObj[i] = deepClone(obj[i]); continue; } clObj[i] = obj[i]; } return clObj; } Y.addnlProp = { fd: 45 }; console.log('Z object after cloning: ', Z); console.log('Y object: ', Y);


In der Konsole sehen wir deutlich, dass das Ändern des
Y
Objekts, das Hinzufügen einer neuen Eigenschaft, das Ändern des
Z
Objekts und das
addnlProp
der
addnlProp
Eigenschaft in seinem Hauptteil nicht erfolgt.
Schritt 4: Ändern Sie die Eigenschaft
x
, die sich im Hauptteil der Objekte
Z
und
Y
und zeigen Sie erneut beide Objekte in der Konsole an:
Yx = 76; console.log('Y object: ', Y); console.log('Z object: ', Z);


Indem wir die gleiche Eigenschaft im Objekt
Y
ändern, beeinflussen wir die Eigenschaft im Körper
Z
Schritt 5: Im letzten Schritt fügen wir zum Vergleich einfach die Eigenschaft
addToZ
mit dem Wert 100 zum Objekt
refToZ
und zeigen alle drei Objekte in der Konsole an:
refToZ.addToZ = 100; console.log('refToZ object: ', refToZ); console.log('Z object: ', Z); console.log('Y object: ', Y);



Durch Ändern des
refToZ
Objekts
refToZ
wir auch
Z
geändert,
Y
nicht betroffen. Daraus schließen wir, dass unsere Funktion ein eigenständiges neues Objekt mit Eigenschaften und deren Werten aus einem vorhandenen Objekt erstellt (der Code zur Implementierung der
deepClone
Funktion befindet sich auf
CodePen ).
Kommen wir zur Implementierung dieser Funktion. Letzterer findet eine Verschachtelung des Objekts, ohne es überhaupt zu wissen. Wie macht sie das? Die Sache ist, dass wir in diesem Fall den bekannten Algorithmus für Graphen verwenden - Tiefensuche. Ein Objekt ist eine Grafik mit einem oder mehreren Zweigen, die wiederum Zweige usw. haben können. Damit wir alles finden können, müssen wir in jeden Zweig und in seine Tiefe gehen, damit wir jeden Knoten im Diagramm finden und seine Werte abrufen können. Deep Search kann auf zwei Arten implementiert werden: Rekursion und Verwendung einer Schleife. Der zweite kann sich als schneller herausstellen, da er den Aufrufstapel nicht ausfüllt, was wiederum die Rekursion bewirkt. Bei der Implementierung der
deepClone
Funktion
deepClone
wir eine Kombination aus Rekursion und Schleife verwendet. Wenn Sie Bücher über Algorithmen lesen möchten, empfehle ich Ihnen, Aditya Bhargava "Grokayem-Algorithmen" oder einen tiefergehenden Thomas Kormen "Algorithmen: Konstruktion und Analyse" zu starten.
Zusammenfassend haben wir Datentypen in JavaScript zurückgerufen und wie sie an Funktionen übergeben werden. Wir haben uns ein einfaches Beispiel für das unabhängige Klonen eines einfachen eindimensionalen Arrays angesehen. Wir haben eine der Standard-Sprachimplementierungen zum Kopieren von Objekten in Betracht gezogen und als Ergebnis eine kleine (in der Größe) Funktion zum unabhängigen tiefen Klonen komplexer Objekte geschrieben. Eine ähnliche Funktion findet ihre Anwendung sowohl auf der Serverseite (Node js), was wahrscheinlicher ist, als auch auf dem Client. Ich hoffe, dieser Artikel hat Ihnen geholfen. Wir sehen uns wieder.