kathi: scope chain

hallo ihr :)

ich bräuchte mal eure hilfe.
und zwar zum einen, was versteht man genau unter einer scope chain und wozu dient sie? ich finde im internet keine für mich hilfreichen informationen :(

zu diesem thema hatten wir noch folgendes script

<script type="text/javascript">  
function scope_test()  
{  
  var x = 7;  
  document.write("In scope_test: x = " + x + ", y = " + y + "<br>");  
  y=12  
}  
  
var x = 5;  
var y = 10;  
  
document.write("vor scope: x = " + x + "; y = " + y + "<br>");  
scope_test();  
document.write("nach scope: x = " + x + "; y = " + y + "<br>");  
  
  
</script>

an diesem sollten wir die scope chain skizzieren. ich habe es mal ausgeführt und man bekommt folgende ausgabe:

vor scope: x = 5; y = 10
In scope_test: x = 7, y = 10
nach scope: x = 5; y = 12

vor scope verstehe ich ja noch, da es die variablen schreibt, bevor funktion scope_test ausgeführt wird. dann wird funktion ausgeführt
also wird das x zur 7, y bleibt bei 10 (da es ja erst nach "document.write" geändert wird).
aber wieso die letzte zeile?

ich hoffe, ihr könnt mir helfen!

danke :)

eure kathi

  1. Hallo,

    aber wieso die letzte zeile?

    Schauen wir uns nochmal die Funktion an:

      
    function scope_test()  
    {  
      var x = 7;  
      document.write("In scope_test: x = " + x + ", y = " + y + "<br>");  
      y=12  
    }  
    
    

    mit "var x" wird eine lokale Variable in der Funktion angelegt. Das bedeutet, die Variable x des äußeren Scope ist in diesem Moment nicht mehr gültig, sondern es gibt ein neues x (mit dem Wert 7).
    Da die Variable lokal ist, wird sie aber beim Verlassen der Funktion wieder weggeräumt, das x ausserhalb der Funktion bekommt von der ganzen Sache nichts mit - und hat daher noch seinen alten Wert (5).

    y=12 hingegen ist nicht lokal definiert. Folglich ist diese Variable global, der Scope ist also der von AUSSERHALB der Funktion. Deswegen wird mit "y=12" auch das y ausserhalb der Funktion verändert.

    Anders erklärt, falls Du mit dem Begriff "Stack" was anfangen kannst:
    "var x=7" legt eine neue Variable auf den Stack. In dem document.write wird nun das x vom Stack genommen, welches am weitesten oben liegt (LIFO), also das x mit Wert 7.

    Für y wird hingegen KEIN neues Element auf den Stack gelegt, bei "y=12" wird das y vom Stack geholt, was am höchsten oben liegt, und das ist das äußere y (mit Wert 10)  - dieses wird dann mit mit einem neuen Wert befüllt (12).

    Hoffe, das hilft Dir weiter.

    Viele Grüße,
    Jörg

    1. sorry, war wohl bei der auswahl des oberthemas vorhin zu schnell. mir ist sehr wohl klar, dass es zwischen js und java einen unterschied gibt. sorry, war mein fehler.

      nein, das ist im übrigen keine hausaufgabe. ich lerne für eine klausur und habe hier zig beispielaufgaben und versuche die durchzuarbeiten, kam hier aber einfach nicht weiter. :(

      aber vielen lieben dank für eure hilfe! jetzt habe ich das ganze schon viel besser verstanden!

  2. Hi,

    du meinst offenbar JavaScript, nicht Java. Ist dir nicht klar, dass das etwas vollkommen anderes ist?

    und zwar zum einen, was versteht man genau unter einer scope chain und wozu dient sie?

    Scope ist der Geltungsbereich einer Variablen.

    Und JavaScript hat eine scope chain, d.h. eine Kette, in der nach einer Variablen gesucht wird, wenn das Objekt, dessen Eigenschaft sie sein soll, nicht explizit angegeben ist.

    </archiv/2009/3/t184896/#m1226489> (auf die scope chain bei Eventhandlern bezogen)

    an diesem sollten wir die scope chain skizzieren.

    Hausaufgabe?

    vor scope: x = 5; y = 10
    In scope_test: x = 7, y = 10
    nach scope: x = 5; y = 12

    vor scope verstehe ich ja noch, da es die variablen schreibt, bevor funktion scope_test ausgeführt wird. dann wird funktion ausgeführt
    also wird das x zur 7,

    Nein, nicht „das“ x, sondern ein ganz anderes x.
    x ist eine lokale Variable in der Funktion. http://de.selfhtml.org/javascript/sprache/variablen.htm

    y bleibt bei 10 (da es ja erst nach "document.write" geändert wird).
    aber wieso die letzte zeile?

    Weil sich das ausserhalb der Funktion definierte x nicht geändert hat, da in der Funktion ein anderes x angesprochen wird.
    Das y hingegen ist das gleiche wie ausserhalb der Funktion.

    MfG ChrisB

    --
    “Whoever best describes the problem is the person most likely to solve the problem.” [Dan Roam]
  3. Hallo,

    und zwar zum einen, was versteht man genau unter einer scope chain und wozu dient sie? ich finde im internet keine für mich hilfreichen informationen :(

    JavaScript hat keinen lexikalischen Scope, sondern nur einen funktionalen. D.h. eine Funktion erzeugt einen neuen Variablen-Geltungsbereich.

    Der oberste Scope ist das globale Objekt, window. Wenn du außerhalb jeder Funktion

    var i = 1;

    schreibst, dann ist es eine globale Variable. Globale Variablen sind Eigenschaften des window-Objektes. Das heißt, obige Anweisung hat die Eigenschaft window.i erzeugt.

    Alle weiteren Scopes werden von Funktionen erzeugt. Beispiel:

    function scope_text () {
       var j = 1;
    }
    scope_test();

    Das »var« vor der Wertzuweisung sorgt bekanntlich dafür, dass es eine lokale Funktionsvariable ist.

    Intern wird folgendes gemacht: Beim Ausführen dieser Funktion legt der JavaScript-Interpreter ein (unsichtbares, nicht zugängliches) Variablenobjekt an und erzeugt dort eine Eigenschaft namens »j«. Und beim Ausführen des Funktionskörpers bekommt sie den Wert 1 zugewiesen.

    Was ist nun die Scope Chain und wann kommt sie ins Spiel?

    Die Scope Chain ist eine Liste von Objekten. Sie kommt ins Spiel, wenn JavaScript einen Bezeichner auflöst.

    Wenn du schreibst:

    alert(j);

    dann muss der JavaScript-Interpreter die Variable j auflösen, also die Stelle im Speicher suchen, wo der zugehörige Wert abgelegt ist.

    (Den Bezeichner »alert« muss er natürlich genauso nachschlagen.)

    Wo sucht der Interpreter nun danach? Nicht bei irgendwelchen Objekten, sondern nacheinander bei den Objekten in der Scope Chain. An jeder Stelle im Programm gibt es eine solche definierte Liste.

    Der erste Eintrag in der Scope Chain ist immer das globale Objekt window. Klar, das ist der oberste Geltungsbereich. Dort wird zuletzt gesucht.

    Wenn der Interpreter eine Funktion ausführt, dann wird die Scope-Liste ergänzt: Nämlich um das Variablenobjekt dieser Funktion. Dort wird zuerst gesucht.

    In der obigen Funktion scope_test() hat die Scope Chain also zwei Einträge:

    1. das globale Objekt window
    2. das (nicht direkt erreichbare) Variablenobjekt der jeweiligen scope_test-Ausführung

    Wenn du in scope_test die Variable j notierst und der Interpreter sie auflöst, dann sucht er diese Liste von hinten durch:

    1. Er sucht erst nach einer lokalen Funktionsvariable. Das bedeutet intern: Er sucht nach einer entsprechenden Eigenschaft beim Variablenobjekt (sozusagen variablenobjekt.j).

    2. Wenn dort keine Eigenschaft mit diesem Namen existiert, geht er weiter in der Liste und sucht beim globalen Objekt (sozusagen window.j). Wenn dort auch nichts gefunden wurde, dann bricht das Programm mit einer Exception ab.

    Damit lässt sich dein Beispiel erklären:

    var x = 5;
    var y = 10;

    Hier legst du zwei globale Variablen an (window.x und window.y).

    document.write("vor scope: x = " + x + "; y = " + y + "<br>");

    Hier notierst du die Bezeichner x und y. Sie werden gemäß der Scope Chain aufgelöst, um zu schauen, welche »Speicherstellen« du damit meinst.

    Da die Scope-Chain an dieser Stelle nur das window-Objekt enthält, ist es klar, dass der Interpreter window.x und window.y findet sowie deren Werte 5 und 10.

    Jetzt führst du scope_test aus:

    scope_test();

    Der Interpreter springt in die Funktion.

    function scope_test()
    {

    Dabei wird wie gesagt ein internes Variablenobjekt angelegt. Und das wird in die Scope-Chain gelegt. Die enthält also jetzt zwei Objekte!

    var x = 7;

    Dies ist eine Variablen-Deklaration, man erkennt sie am »var« am Anfang.

    Innerhalb einer Funktion wird damit eine lokale Funktionsvariable angelegt.

    Wie gesagt, intern wird dabei eine Eigenschaft beim Variablenobjekt erzeugt. Veranschaulicht: variablenobjekt.x = 7.

    document.write("In scope_test: x = " + x + ", y = " + y + "<br>");

    Hier werden wieder zwei Bezeichner notiert und nacheinander bei zwei Objekten (Variablenobjekt, globales Objekt window) nachgeschlagen.

    x wird beim Variablenobjekt gefunden. Der Wert ist 7.
    Weil x bereits gefunden wurde, wird erst gar nicht beim darüberliegenden Objekt in der Scope Chain (window) gesucht.

    y wird nicht beim Variablenobjekt gefunden.
    Also wird nach einer entsprechenden globalen Variable gesucht. window.y existiert und dessen Wert ist 10.

    y=12

    Das ist eine Wertzuweisung. Und um die durchzuführen, muss der Browser entscheiden, an welchem Objekt er y sucht. Das funktioniert ebenfalls über die Scope Chain:

    Existiert existiert eine lokale Variable namens y, also variablenobjekt.y? Nein.
    Also weiter: Existiert window.y? Ja. Also wird ihr der Wert 12 zugewiesen.

    Randnotiz: Wenn window.y noch nicht existieren würde, würde er der Interpreter in diesem Fall einfach anlegen. Ein einfaches y = 12 in einer Funktion sorgt dafür, dass window.y angelegt wird, wenn man die Variable nicht mit var y; als lokal deklariert hat.

    }

    Tja, jetzt endet die Ausführung der Funktion. Und damit springt der Interpreter zurück in einen vorherigen Geltungsbereich - und löscht das Variablenobjekt.

    Damit fällt es auch aus der Scope Chain. Diese besteht jetzt nur noch aus dem globalen Objekt window.

    document.write("nach scope: x = " + x + "; y = " + y + "<br>");

    x und y bedeuten hier window.x und window.y.

    Dessen Werte sind 5 und 12.

    5, weil window.x im Laufe der Funktionsausführung unangetastet blieb. Was in der Funktion verändert wurde, war lediglich die lokale Funktionsvariable x! Die ist mittlerweile schon vergessen und gelöscht. Daher ist der Wert von window.x derselbe wie vor dem Funktionsaufruf.

    Ganz anders window.y. Bei der Ausführung von scope_test() wurde dessen Wert geändert. Daher ist der neue Wert 12.

    aber wieso die letzte zeile?

    Im Grunde ist es der Unterschied zwischen globalen Variablen (die kleben als Eigenschaften beim window-Objekt) und lokalen Funktionsvariablen (die kleben an einem unsichtbaren Variablenobjekt).

    Es gibt hier sowohl eine globale Variable namens x als auch eine gleichnamige lokale Variable. Das ist problemlos möglich, ohne dass die sich in die Quere kommen.

    Wenn man innerhalb der Funktion dann »x« schreibt, dann meint dieser Bezeichner immer die lokale Variable (wegen der Variablendeklaration »var x«!). Wenn sich deren Wert ändert (variablenobjekt.x), dann bleibt der Wert der gleichnamigen globalen (window.x) unangetastet.

    Die Frage »Welche Variable ist mit x denn nun gemeint?« beantwortet sich der JavaScript-Interpreter eben dadurch, dass er die Objekte in der Scope-Chain durchsucht.

    Um den Unterschied nochmal klar zu machen, dein Code nochmal in einen Pseudocode übersetzt, der zeigt, was bei der Ausführung tatsächlich passiert.

    window = das globale Objekt, an dem globale Variablen gespeichert werden
    variablenobjekte = das (interne, hier sichtbar gemachte) Objekt mit lokalen Funktionsvariablen

    function scope_test()
    {
      variablenobjekt.x = 7;   // Das bedeutet: window.x bleibt unangetastet!
      document.write("In scope_test: x = " + variablenobjekt.x + ", y = " + window.y + "<br>");
      window.y = 12
    }

    window.x = 5;
    window.y = 10;

    document.write("vor scope: x = " + window.x + "; y = " + window.y + "<br>");
    scope_test();
    document.write("nach scope: x = " + window.x + "; y = " + window.y + "<br>");

    Grüße, IR