Referenzen und Objekte bei Javascript
DaBear
- javascript
Doofer Titel... aber naja. Ich hab folgendes Problem:
function A(a)
{
var a = a;
//...
}
function B(a)
{
var a = a;
this.tuwas = tuwas()
{
a = new A();
//a ausgeben
}
}
function C(meinarray)
{
var meinA = new A(meinarray);
this.tuwas2 = tuwas2()
{
var meinB = new B(meinA);
meinB.tuwas();
//Ausgabe von meinA
}
}
Im Beispiel ist ungefähr das Kommandomuster umgesetzt.
Zunächst wird ein Objekt von C erschaffen und kriegt ein Array übergeben, worauf C ein neues A kreiert. Dann wird von C die funktion tuwas2() aufgerufen. Hier wird ein neues B erschaffen und das B kriegt das bereits bekannte A übergeben (als Referenz oder?). Nun wird vom B die Methode tuwas() aufgerufen, die das A quasi löscht bzw. halt ein neues A ohne Array erzeugt. Wenn man nun aber nach diesem Aufruf das A ausgibt, dann ist es plötzlich das alte A! Es wird vom B nicht gelöscht, die Arraywerte sind erhalten geblieben. Wenn ich jedoch innerhalb von B das A nach dem Löschen ausgebe, dann ist das A gelöscht.
Wie kommt das?
Hi,
Nun wird vom B die Methode tuwas() aufgerufen, die das A quasi löscht bzw. halt ein neues A ohne Array erzeugt.
Nein, gelöscht wird da überhaupt nichts - lediglich die lokale Variable a wird überschrieben.
Wenn man nun aber nach diesem Aufruf das A ausgibt, dann ist es plötzlich das alte A! Es wird vom B nicht gelöscht, die Arraywerte sind erhalten geblieben. Wenn ich jedoch innerhalb von B das A nach dem Löschen ausgebe, dann ist das A gelöscht.
Wie kommt das?
Weil a in B eine lokale Variable ist.
MfG ChrisB
Hi,
Nun wird vom B die Methode tuwas() aufgerufen, die das A quasi löscht bzw. halt ein neues A ohne Array erzeugt.
Nein, gelöscht wird da überhaupt nichts - lediglich die lokale Variable a wird überschrieben.
Mein ich doch ;)
Wenn man nun aber nach diesem Aufruf das A ausgibt, dann ist es plötzlich das alte A! Es wird vom B nicht gelöscht, die Arraywerte sind erhalten geblieben. Wenn ich jedoch innerhalb von B das A nach dem Löschen ausgebe, dann ist das A gelöscht.
Wie kommt das?
Weil a in B eine lokale Variable ist.
Ja aber a ist doch eine Referenz oder nicht? Also müsste doch das Objekt selbst geändert werden und die Änderung auch noch bleiben, nachdem B beendet ist.
Wie erreiche ich es denn (eleganzt), dass das Objekt danach geändert bleibt?
Hallo,
Im Beispiel ist ungefähr das Kommandomuster umgesetzt.
Das ist mir zu ungefähr. Zeig' doch mal das kurzes Beispiel mit allen Ausgaben, so dass man nachvollziehen kan, was du genau meinst.
Gruß, Don P
Hallo,
Im Beispiel ist ungefähr das Kommandomuster umgesetzt.
Das ist mir zu ungefähr. Zeig' doch mal das kurzes Beispiel mit allen Ausgaben, so dass man nachvollziehen kan, was du genau meinst.
Das geht doch aus dem Code klar hervor. Wenn du möchtest, dann mach ich gerne auch ein ausführbares Beispiel draus, was man nur in eine html-Datei packen muss.
Trotzdem bleibt die Frage, warum die Methode tuwas() nicht die Referenz ändern/überschreibt. Wenn tuwas() von der Referenz eine Methode aufruft, die das Array in der Referenz löscht, dann funktioniert das wunderbar. Wieso wird die Referenz dann, wenn man ihr einen neuen Wert bzw. ein neues Pbjekt zuweist, nicht überschrieben, sondern plötzlich als lokale Variable verwendet. Das erscheint mir etwas willkürlich.
Hi,
Das ist mir zu ungefähr. Zeig' doch mal das kurzes Beispiel mit allen Ausgaben, so dass man nachvollziehen kan, was du genau meinst.
Das geht doch aus dem Code klar hervor.
Nicht wirklich - da definierst du nur Funktionsobjekte, ohne von denen dann auch Instanzen zu erzeugen. Und die tuwas-Methoden sind auch syntaktisch fehlerhaft notiert.
Wieso wird die Referenz dann, wenn man ihr einen neuen Wert bzw. ein neues Pbjekt zuweist, nicht überschrieben, sondern plötzlich als lokale Variable verwendet.
Du gibst doch explizit an, dass du eine lokale Variable haben möchtest.
MfG ChrisB
Hi,
Das ist mir zu ungefähr. Zeig' doch mal das kurzes Beispiel mit allen Ausgaben, so dass man nachvollziehen kan, was du genau meinst.
Das geht doch aus dem Code klar hervor.
Nicht wirklich - da definierst du nur Funktionsobjekte, ohne von denen dann auch Instanzen zu erzeugen. Und die tuwas-Methoden sind auch syntaktisch fehlerhaft notiert.
So besser?
function A(a)
{
var a = a;
this.ausgeben = function ausgeben()
{
return a;
}
}
function B(a)
{
var a = a;
this.tuwas = function tuwas()
{
a = new A(new Array());
//a ausgeben
}
}
function C(meinarray)
{
var meinA = new A(meinarray);
this.tuwas2 = function tuwas2()
{
var meinB = new B(meinA);
meinB.tuwas();
//Ausgabe von meinA
}
this.ausgeben = function ausgeben()
{
return meinA.ausgeben();
}
}
var c = new C(new Array("1", "2", "3"));
//meinA hat jetzt das Array gespeichert
c.tuwas2();
//Gibt jetzt kein leeres Array aus, sondern das Array mit den 3 Strings
c.ausgeben()
Wenn ich von B hingegen eine Methode von A aufrufen lassen, mit der A etwas in sich selbst ändert, dann bleibt die Änderung "für immer".
Wie erreiche ich es nun, dass B quasi A "löscht"?
Ich könnte in tuwas2() natürlich einfach "meinA = new A(new Array());" schreiben, aber das möchte ich nicht. Geht das auch anders?
Ist das Beispiel immernoch zu schlecht oder wisst ihr auch nicht weiter?
Hi,
Das ist mir zu ungefähr. Zeig' doch mal das kurzes Beispiel mit allen Ausgaben, so dass man nachvollziehen kan, was du genau meinst.
Das geht doch aus dem Code klar hervor.
Da geht nichts klar hervor!
function A(a)
{
var a = a;this.ausgeben = function ausgeben()
{
return a;
}
}function B(a)
{
var a = a;this.tuwas = function tuwas()
{
a = new A(new Array());
//a ausgeben
}
}function C(meinarray)
{
var meinA = new A(meinarray);this.tuwas2 = function tuwas2()
{
var meinB = new B(meinA);
meinB.tuwas();
//Ausgabe von meinA
}this.ausgeben = function ausgeben()
{
return meinA.ausgeben();
}
}var c = new C(new Array("1", "2", "3"));
//meinA hat jetzt das Array gespeichert
c.tuwas2();
//Gibt jetzt kein leeres Array aus, sondern das Array mit den 3 Strings
c.ausgeben()
Ich glaube, du schmeißt da einiges durcheinander.
Hier behauptest du, irgendwelche Sachen zu machen:
> Wenn ich von B hingegen eine Methode von A aufrufen lassen, mit der A etwas in sich selbst ändert, dann bleibt die Änderung "für immer".
> Wie erreiche ich es nun, dass B quasi A "löscht"?
> Ich könnte in tuwas2() natürlich einfach "meinA = new A(new Array());" schreiben, aber das möchte ich nicht. Geht das auch anders?
Wahrscheinlich machst du aber ganz andere Sachen als du denkst!!!
Zeig doch mal den Code, der angeblich das Beschriebene machen soll.
Ich sehe auch nicht, daß irgendwo etwas ausgegeben wird. Es wird immer nur etwas zurückgegeben.
Gruß
peter
Hallo,
So besser?
Ja, allerdings.
function A(a)
{
var a = a;this.ausgeben = function ausgeben()
{
return a;
}
}function B(a)
{
var a = a;this.tuwas = function tuwas()
{
a = new A(new Array());
//a ausgeben
}
}function C(meinarray)
{
var meinA = new A(meinarray);this.tuwas2 = function tuwas2()
{
var meinB = new B(meinA);
meinB.tuwas();
//Ausgabe von meinA
}this.ausgeben = function ausgeben()
{
return meinA.ausgeben();
}
}var c = new C(new Array("1", "2", "3"));
//meinA hat jetzt das Array gespeichert
Genauer: c verweist jetzt auf ein C-Objekt, und das kennt eine Variable meinA, die auf ein A-Objekt verweist, welches eine Variable a kennt, die auf das übergebene Array verweist.
> c.tuwas2();
> //Gibt jetzt kein leeres Array aus, sondern das Array mit den 3 Strings
c.tuwas2 erzeugt und speichert zunächst in meinB ein B-Objekt, welches das A-Objekt (meinA) als Parameter bekommt und dieses in seiner Variablen a speichert:
> `var meinB = new B(meinA);`{:.language-javascript}
Dann ruft c.tuwas2 noch die Methode tuwas seines B-objekts auf, die seine eigene Variable a mit einem leeren Array überschreibt (nur im B-objekt):
> `meinB.tuwas();`{:.language-javascript}
Ausgegeben wird dabei nichts.
> `c.ausgeben()`{:.language-javascript}
Die ausgeben-Methode des C-Objekts ruft nun die gleichnamige Methode seines in meinA gespeicherten A-Objekts auf, welche das in seiner Variablen a nach wie vor referenzierte, ursprüngliche Array zurückgibt.
Was hast du erwartet?
Das B-Objekt kann seine eigene Variable a so oft überschreiben wie es will, kein anderes Objekt bekommt davon etwas mit.
> Wenn ich von B hingegen eine Methode von A aufrufen lassen, mit der A etwas in sich selbst ändert, dann bleibt die Änderung "für immer".
Ist klar.
> Wie erreiche ich es nun, dass B quasi A "löscht"?
Vielleicht, indem es "hingegen eine Methode von A" aufruft, "mit der A etwas in sich selbst ändert" ?
> Ich könnte in tuwas2() natürlich einfach "meinA = new A(new Array());" schreiben, aber das möchte ich nicht.
Warum nicht?
> Geht das auch anders?
Wenn du – wie im gezeigten Beispiel – sogenannte Closures verwendest (deine Variablen a in den A- und B-Objekten) dann kann auf diese nur von Methoden der Objekte zugegriffen werden, in denen sie auch definiert sind: Eine Methode im Konstruktor von A kann auf die Variable a einer A-Instanz zugreifen, und eine eine Methode im Konstruktor von B kann auf die Variable a einer B-Instanz zugreifen.
Aber die Methode eine B-Instanz kann niemals direkt auf die Variable a einer A-Instanz zugreifen, und umgekehrt auch nicht.
Wenn allerdings noch woanders eine Referenz auf denselben Wert existiert – also hier das Array – dann kann man diese andere Referenz verwenden, um das Array zu ändern, auf das in Closure-Variablen verwiesen wird.
Gruß, Don P
c.tuwas2 erzeugt und speichert zunächst in meinB ein B-Objekt, welches das A-Objekt (meinA) als Parameter bekommt und dieses in seiner Variablen a speichert
Noch genauer formuliert:
c.tuwas2 erzeugt und speichert zunächst in meinB die Referenz auf eine neue B-Instanz, welche die Referenz auf die A-Instanz (meinA) als Parameter bekommt und diese in seiner Variablen a speichert (im B-Objekt)
Dann ruft c.tuwas2 noch die Methode tuwas seines B-objekts auf, die seine eigene Variable a mit einem leeren Array überschreibt (nur im B-objekt)
Noch genauer formuliert:
Dann ruft c.tuwas2 noch die Methode tuwas seiner B-Instanz auf, welche die zuerst gespeicherte Referenz in seiner eigenen Variable a nun durch die Referenz auf ein leeres Array ersetzt (nur im B-objekt)
Gruß, Don P
Noch genauer formuliert:
Dann ruft c.tuwas2 noch die Methode tuwas seiner B-Instanz auf, welche die zuerst gespeicherte Referenz in seiner eigenen Variable a nun durch die Referenz auf ein leeres Array ersetzt (nur im B-objekt)
Angenommen ich kann _nur_ den Code in B ändern:
Wie erreiche ich es, in der Instanz von B die Referenz von der Instanz von C (die die Instanz von C in der Variable meinA gespeichert hat) auf eine andere Instanz von A zeigen zu lassen?
Was hast du erwartet?
Das B-Objekt kann seine eigene Variable a so oft überschreiben wie es will, kein anderes Objekt bekommt davon etwas mit.
Ja, ich denke mir ist jetzt klar, warum es so funktioniert, wie es funktioniert. Das ist doch schonmal gut =)
Wenn ich von B hingegen eine Methode von A aufrufen lassen, mit der A etwas in sich selbst ändert, dann bleibt die Änderung "für immer".
Ist klar.
Wie erreiche ich es nun, dass B quasi A "löscht"?
Vielleicht, indem es "hingegen eine Methode von A" aufruft, "mit der A etwas in sich selbst ändert"?
Das hat aber Nachteile. Nämlich erstens, dass ich in A eine solche Methode schreiben muss (was ich vielleicht gar nicht kann, weil ich die A Interna gar nicht kenne[n will]). Zweitens, dass ich das nächste mal wenn ich in A irgendetwas ändere auch diese Methode anpassen muss. Das erhöht die Fehleranfälligkeit, denn wenn ich einfach ein neues A erzeuge, kann ich zu 100% sicher sein, dass ich eine frische Instanz habe.
Ich könnte in tuwas2() natürlich einfach "meinA = new A(new Array());" schreiben, aber das möchte ich nicht.
Warum nicht?
Weil das das Befehlsmuster unterlaufen würde. Dann hat der Befehl ja nichts mehr zu tun. Das führt dann auch dazu, dass ich in der Klasse C Code-Teile drin habe, die dort semantisch nichts zu suchen haben.
Geht das auch anders?
Wenn du – wie im gezeigten Beispiel – sogenannte Closures verwendest (deine Variablen a in den A- und B-Objekten) dann kann auf diese nur von Methoden der Objekte zugegriffen werden, in denen sie auch definiert sind: Eine Methode im Konstruktor von A kann auf die Variable a einer A-Instanz zugreifen, und eine eine Methode im Konstruktor von B kann auf die Variable a einer B-Instanz zugreifen.
Aber die Methode eine B-Instanz kann niemals direkt auf die Variable a einer A-Instanz zugreifen, und umgekehrt auch nicht.
Wenn allerdings noch woanders eine Referenz auf denselben Wert existiert – also hier das Array – dann kann man diese andere Referenz verwenden, um das Array zu ändern, auf das in Closure-Variablen verwiesen wird.
Ich möchte aber nicht dass Array in A löschen, sondern die ganze Instanz von A durch eine frische Instanz ersetzen. Oder worauf wolltest du hinaus?
function A(a)
{
var a = a;
Diese Zuweisung ist Quatsch. a ist schon eine lokale Variable. var a = a; hat keinen Effekt. Du kannst die ganze Zeile weglassen.
this.ausgeben = function ausgeben()
{
return a;
}
}function B(a)
{
var a = a;this.tuwas = function tuwas()
{
a = new A(new Array());
//a ausgeben
}
}function C(meinarray)
{
var meinA = new A(meinarray);this.tuwas2 = function tuwas2()
{
var meinB = new B(meinA);
meinB.tuwas();
//Ausgabe von meinA
}this.ausgeben = function ausgeben()
{
return meinA.ausgeben();
}
}var c = new C(new Array("1", "2", "3"));
//meinA hat jetzt das Array gespeichert
c.tuwas2();
//Gibt jetzt kein leeres Array aus, sondern das Array mit den 3 Strings
c.ausgeben()
Wie kommst du darauf, dass es einen leeren Array ausgeben sollte?
Wieso sollte sich an dem Wert von meinA etwas ändern, wenn du eine B-Instanz erstellst, ihr meinA übergibst und in einer B-Methode den Wert dieses Konstruktor-Parameters änderst?
Wenn ich von B hingegen eine Methode von A aufrufen lassen, mit der A etwas in sich selbst ändert, dann bleibt die Änderung "für immer".
Wie erreiche ich es nun, dass B quasi A "löscht"?
Anscheinend missverstehst du, wie private Objekte funktionieren. Und du missverstehst, dass sich der Wert einer Variablen nicht ändert, wenn du einer anderen Variable, die vorher zufällig denselben Wert hat, einen anderen zuweist.
Du machst hier im Grunde folgendes:
var a = 1;
var b = a;
b = 2;
alert(a);
und wunderst dich, dass a nicht gleich 2 ist.
Du übergibst eine A-Instanz als Parameter an den B-Konstruktor. Dort wird eine lokale Variable erzeugt, die in den verschachtelten Methoden (Closures) verfügbar ist. Wenn du dieser lokalen Variablen nun einen neuen Wert gibst, so ändert sich doch nicht automatisch der Wert der Variable meinA in einer C-Instanz.
Ich könnte in tuwas2() natürlich einfach "meinA = new A(new Array());" schreiben, aber das möchte ich nicht.
Wieso nicht? Wieso sollte eine andere (Pseudo-)Klasse auch die private Variable der C-Instanz ändern dürfen? Dann ergäbe die Trennung ergäbe keinen Sinn.
Geht das auch anders?
Dein Beispiel ist äußerst wirr. Wieso wrappst du einen Array mehrere Male? Zeige mal ein tatsächliches Beispiel ohne A, B und C, sondern mit einem nachvollziehbaren Anwendungsfall.
Mathias
Doofer Titel... aber naja. Ich hab folgendes Problem:
function A(a)
{
var a = a;
//...
}function B(a)
{
var a = a;this.tuwas = tuwas()
{
a = new A();
//a ausgeben
}
}function C(meinarray)
{
var meinA = new A(meinarray);this.tuwas2 = tuwas2()
{
var meinB = new B(meinA);
meinB.tuwas();
//Ausgabe von meinA
}
}
>
> Im Beispiel ist ungefähr das Kommandomuster umgesetzt.
> Zunächst wird ein Objekt von C erschaffen und kriegt ein Array übergeben....
Nein! Zunächst passiert erstmal gar nichts. Solange C nicht auzfgerufen wird, wird weder von C etwas erschaffen noch wird etwas übergeben.
Oder hast du mit deiner Aussage gemeint, daß ein Objekt C erschaffen wird?
Also mal angenommen, C wird aufgerufen und dabei auch wirklich ein Array an C übergeben:
> Zunächst wird ein Objekt von C erschaffen und kriegt ein Array übergeben, worauf C ein neues A kreiert.
Nein.
Es wird eine lokale Variable meinA erzeugt.
Diese ist nur in C erreichbar.
Es wird kein neues A kreiert sondern eine Instanz des bestehenden A erzeugt.
In der lokalen Variable meinA wird eine Referenz auf die erzeugte Instanz von A gespeichert.
> Dann wird von C die funktion tuwas2() aufgerufen.
Nein, wird Sie nicht.
Aber mal angenommen, Sie würde aufgerufen werden:
> Hier wird ein neues B erschaffen und das B kriegt das bereits bekannte A übergeben (als Referenz oder?).
Es wird eine Instanz von B erzeugt und eine Referenz auf die Instanz in der lokalen Variable meinB gespeichert.
Der Instanz von B wird eine Referenz auf die zuvor erzeugte Instanz von A übergeben.
> Nun wird vom B die Methode tuwas() aufgerufen, die das A quasi löscht bzw. halt ein neues A ohne Array erzeugt.
Beim Erzeugen der Instanz von B wurde in der lokalen Variable a eine Referenz auf meinA gespeichert (nicht schön, daß da alles a heißt).
Beim Aufruf von tuwas wird eine neue Instanz von A erzeugt und eine Referenz auf diese neue Instanz von A in a gespeichert.
Die zuerst (in C) erzeugte Instanz von A bleibt unverändert bestehen. Eine Referenz auf diese Instanz ist noch in meinA gespeichert (innerhalb von C).
> Wenn man nun aber nach diesem Aufruf das A ausgibt, dann ist es plötzlich das alte A! Es wird vom B nicht gelöscht, die Arraywerte sind erhalten geblieben. Wenn ich jedoch innerhalb von B das A nach dem Löschen ausgebe, dann ist das A gelöscht.
Du bekommst das angezeigt, was du anzeigen lässt.
>
> Wie kommt das?
function A(a)
{
var a = a;
//...
}function B(a)
{
var a = a;this.tuwas = tuwas()
{
a = new A();
//a ausgeben
}
}function C(meinarray)
{
var meinA = new A(meinarray);this.tuwas2 = tuwas2()
{
var meinB = new B(meinA);
meinB.tuwas();
//Ausgabe von meinA
}
}
> >
> > Im Beispiel ist ungefähr das Kommandomuster umgesetzt.
> > Zunächst wird ein Objekt von C erschaffen und kriegt ein Array übergeben....
>
> Nein! Zunächst passiert erstmal gar nichts. Solange C nicht auzfgerufen wird, wird weder von C etwas erschaffen noch wird etwas übergeben.
> Oder hast du mit deiner Aussage gemeint, daß ein Objekt C erschaffen wird?
>
> Also mal angenommen, C wird aufgerufen und dabei auch wirklich ein Array an C übergeben:
> > Zunächst wird ein Objekt von C erschaffen und kriegt ein Array übergeben, worauf C ein neues A kreiert.
> Nein.
> Es wird eine lokale Variable meinA erzeugt.
> Diese ist nur in C erreichbar.
> Es wird kein neues A kreiert sondern eine Instanz des bestehenden A erzeugt.
> In der lokalen Variable meinA wird eine Referenz auf die erzeugte Instanz von A gespeichert.
>
> > Dann wird von C die funktion tuwas2() aufgerufen.
> Nein, wird Sie nicht.
> Aber mal angenommen, Sie würde aufgerufen werden:
>
> > Hier wird ein neues B erschaffen und das B kriegt das bereits bekannte A übergeben (als Referenz oder?).
> Es wird eine Instanz von B erzeugt und eine Referenz auf die Instanz in der lokalen Variable meinB gespeichert.
> Der Instanz von B wird eine Referenz auf die zuvor erzeugte Instanz von A übergeben.
>
> > Nun wird vom B die Methode tuwas() aufgerufen, die das A quasi löscht bzw. halt ein neues A ohne Array erzeugt.
>
> Beim Erzeugen der Instanz von B wurde in der lokalen Variable a eine Referenz auf meinA gespeichert (nicht schön, daß da alles a heißt).
> Beim Aufruf von tuwas wird eine neue Instanz von A erzeugt und eine Referenz auf diese neue Instanz von A in a gespeichert.
>
> Die zuerst (in C) erzeugte Instanz von A bleibt unverändert bestehen. Eine Referenz auf diese Instanz ist noch in meinA gespeichert (innerhalb von C).
Okay soweit so gut.
C (bzw die Instanz von C) hat ja nun eine Referenz auf die in C erzeugte Instanz von A. Wenn ich nun möchte, dass nach tuwas() diese Referenz von C auf ein neue von der Instanz von B erschaffene Instanz von A zeigt, was muss ich dann tun?
B müsste ja dann keine \_Referenz\_ auf die Referenz von C (also hier meinA) speichern, sondern B müsste direkt die Referenz von C selbst speichern und diese dann Überschreiben. D.h. man würde jetzt eigentlich die Referenz auf die Referenz dereferenzieren. Aber das geht in Javascript nicht.
Was bleiben mir für Möglichkeiten?
Hi,
Was bleiben mir für Möglichkeiten?
Wofür? Was willst du eigentlich?
Gruß
Peter