Pass By Value vs Pass By Reference in JavaScript

Wenn Sie neu in JavaScript sind, sind Sie wahrscheinlich bereits auf einige der lustigen Verhaltensweisen gestoßen, die diese Sprache zu bieten hat (Ausstellung A). Zunaechst, Diese seltsamen Macken mögen lächerlich und frustrierend erscheinen, Aber ich verspreche, dass hinter all diesem Wahnsinn eine Methode steckt.

Eine der schwierigsten Hürden, die es meiner bescheidenen Meinung nach zu überwinden gilt, ist der Unterschied zwischen dem Übergeben nach Wert und dem Übergeben nach Referenz. Warum ist dieses Konzept so schwierig? Für den Anfang können Sie sicherlich ziemlich weit kommen, ohne wirklich zu verstehen, wie JavaScript mit primitiven Werten und Referenzwerten interagiert. Dies kann und wird in den meisten Fällen zu einer Menge von Fehlern führen, die schwer aufzuspüren und ärgerlich zu beheben sind. Zweitens ist dies ein Konzept, das in technischen Interviews auftauchen wird, also wird es als eine riesige rote Fahne gegen Sie zählen, wenn Sie es nicht verstehen.

Fürchte dich nicht, Mitleser! Lassen Sie die Ausbildung beginnen …

Primitive Datentypen

In JavaScript können wir Datentypen in zwei verschiedene Buckets unterteilen, primitive Datentypen und Objekte.

Diagramm zur Veranschaulichung der primitiven Datentypen oder Werte und der Objekttypen oder Referenzwerte

In JavaScript gibt es sechs primitive Datentypen: string, number, boolean, undefined, null, und symbol ab ES6.

Primitive Datentypen werden nach Wert übergeben oder kopiert und sind unveränderlich, was bedeutet, dass der vorhandene Wert nicht wie ein Array oder ein Objekt geändert werden kann. Schauen wir uns den folgenden Code an, um dies in Aktion zu sehen.

Erstellt mit jsbin.com

Hier haben wir zwei Variablen erstellt, x = 10 und y = x. Da 10 eine Zahl und ein primitiver Wert ist, kopieren wir beim Setzen von y = x tatsächlich den Wert, dh 10 , und weisen ihn y zu. Wir können dies auch anhand der folgenden Tabelle visualisieren.

Wenn wir den Wert von x ändern würden, würden wir sehen, dass y seinen Wert von 10 behält. Dies liegt wiederum daran, dass primitive Werte kopiert werden, sodass der Wert von y unabhängig vom Wert von x ist. Betrachten Sie es als eine Fotokopie eines Bildes. Nachdem Sie die Kopie erstellt haben, haben Sie zwei identische Bilder: ein Original und ein Faksimile. Wenn Sie das Original halbieren würden, würde nur das Original geändert und das Faksimile würde genau gleich bleiben.

Wir haben den Wert von x überschrieben, aber y bleibt gleich

Referenzobjekte

Objekte hingegen werden als Referenz übergeben und zeigen auf einen Speicherort für den Wert, nicht auf den Wert selbst. Schauen wir uns das in unserem Code an.

Die Variablen x und y zeigen jetzt auf Objekte und nicht auf primitive Datentypen

In diesem Beispiel ist x jetzt ein Objekt, das auf {dog: "poodle"} zeigt. Wenn wir die Variable y erstellen und ihr den Wert x zuweisen, können wir jetzt auf die verschiedenen Eigenschaften von x zugreifen, einschließlich des Werts für dog, dh "poodle". Dies scheint genau die gleiche Logik zu sein, die für primitive Werte verwendet wird, aber werfen wir einen Blick auf unser Handy-Dandy-Diagramm unten, um den subtilen, aber wichtigen Unterschied zu sehen.

Sowohl x als auch y zeigen auf eine (erfundene) Adresse im Speicher, die einen Verweis auf das Objekt

Nun sieht dieses Diagramm ein wenig anders aus, als wenn unsere Variablen x und y primitive Datentypen enthielten. In dieser Version sehen wir, dass die Werte für x und y keine Datentypen sind, sondern Verweise auf eine Adresse im Speicher, tatsächlich dieselbe Adresse! Schauen wir uns nun an, was mit x passiert, wenn wir eine neue Eigenschaft von size hinzufügen y

x gibt immer noch ein Objekt zurück, aber jetzt hat es auch eine zusätzliche Eigenschaft von size! Dies liegt wiederum daran, dass sowohl x als auch y auf dasselbe Referenzobjekt zeigen, sodass alle an einer Variablen vorgenommenen Änderungen in der anderen sichtbar sind.

Diagramm zeigt, wie eine Änderung in y den Referenzwert aktualisiert, der mit x geteilt wird

Um mir zu helfen, mich an dieses Konzept zu erinnern, stelle ich mir Referenzwerte gerne als Haus und die Variablen als Personen vor, die in diesem Haus leben. Alle Bewohner (Variablen) können „Ich habe ein Haus“ sagen und auf dasselbe Haus zeigen. Wenn ein einzelner Bewohner beschließt, das Haus gelb zu streichen, haben jetzt alle Bewohner ein gelbes Haus, weil es geteilt wird.

Schauen wir uns ein weiteres Beispiel an, das eine Vielzahl von Referenzobjekten enthält.

In diesem Code beginnen wir mit einer Variablen person , die Eigenschaften von name, age und hobbies enthält. Wenn wir dieses Objekt auf die Konsole drucken, erhalten wir genau das, was wir erwarten — dasselbe Objekt, das wir gerade erstellt haben.

Als nächstes haben wir eine Funktion namens changePerson , die ein Argument aufnimmt, einige Änderungen vornimmt und dann ein Objekt zurückgibt. Wenn wir die Variable thirdPerson erstellen, rufen wir die FunktionchangePerson auf, indem wir unser ursprüngliches Objekt person übergeben. Das Interessante ist, was passiert, wenn wir wieder auf die Konsole thirdPerson und person drucken.

Beachten Sie, dass console.log(thirdPerson) ein ganz neues Objekt mit neuen Eigenschaften zurückgibt. Sehen Sie sich nun an, was console.log(person) zurückgibt. Dies ähnelt unserem ursprünglichen Objekt, enthält jedoch neue Eigenschaftswerte, die in unserer Funktion changePerson eingeführt wurden.

Auf Gleichheit prüfen

Schauen wir uns abschließend an, wie sich primitive Datentypen und Referenzobjekte mit Gleichheitsoperatoren verhalten.

Wenn es um primitive Datentypen geht, spielt es keine Rolle, was sich rechts vom Zeichen = befindet, solange die Werte gleich sind. Wir können dies oben mit den Variablen a und b sehen, die unterschiedlich geschrieben sind, aber denselben Wert erhalten, wenn wir den === , den strikten Gleichheitsoperator, verwenden.

Das Gegenteil gilt im zweiten Beispiel für dog und cat. Obwohl es den Anschein hat, dass sie identische Werte enthalten, ist ein Array und ein Referenzobjekt, was bedeutet, dass === überprüft, ob sowohl dog als auch cat denselben Verweis auf den Wert im Speicher haben. Andererseits ist bird === dog wahr, weil sie dasselbe Referenzobjekt haben.

hund und Vogel haben dieselbe Referenz, während Katze dies nicht tut, obwohl sie ein identisches Array haben

Fazit

Und damit ist unsere Einführung in Pass by value vs Pass by reference abgeschlossen. Es gibt weitere Themen, die unter diesem grundlegenden Dach behandelt werden können, einschließlich dessen, was passiert, wenn eine Referenz überschrieben wird oder verloren geht, wie eine Referenz kopiert wird, um ein neues Objekt zu erstellen UND sicherzustellen, dass die Kopie eine tiefe Kopie ist, um nur einige zu nennen. Ich würde empfehlen, sich die Ressourcen anzusehen, die ich unten verwendet habe und die einige dieser zusätzlichen Themen ausführlicher behandeln.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.