molily: Scope Chain und with

Beitrag lesen

Hallo,

immer wenn du einen Bezeichner notierst, z.B. »addEventListener«, dann greift die Identifier Resolution. Sprich, der JavaScript-Interpreter löst den Namen zu einem Objekt auf. Diese Namensauflösung erfolgt nach festgelegten Regeln. Und zwar schaut der Interpreter nacheinander an einer Kette von Objekten nach. Diese Kette ist die sogenannte Scope Chain. Die enthält standardmäßig das globale Objekt window sowie, innerhalb von Funktionen, interne Variablenobjekte, an denen lokale Funktionsvariablen gespeichert werden.

Wenn du irgendwo »addEventListener« notierst, dann geht der Interpreter also einfach die Scope Chain durch, um die entsprechende Methode zu finden. Wenn keine lokale Variable dieses Namens existiert und keine in einer höherliegenden Funktion, dann wird der Interpreter bei window.addEventListener fündig.

with macht nun, wie Don P sagt, nichts anderes, als diese Scope Chain um ein Objekt zu erweitern, nämlich an erster Stelle. In deinem Beispiel ist das die HTMLCollection, die getElementsByClassName zurückgibt.

<div class="dropBox">foo</div>  
<script>  
[code lang=javascript]function test () {  
  with(document.getElementsByClassName("dropBox"))  {  
    addEventListener("dragover", dragover, false);  
    addEventListener("drop", drop, false);  
  }  
}  
test();

</script>[/code]

Der Bezeichner addEventListener wird hier an drei Objekten gesucht:
1. an der HTMLCollection
2. am Variablenobjekt des Aufrufs der Funktion test
3. am globalen window-Objekt

Bei 1. und 2. wird der Interpreter nicht fündig.
alert(document.getElementsByClassName("dropBox").addEventListener);
gibt »undefined« aus. Eine lokale Variable namens addEventListener existiert auch nicht.

Was also passiert: Du registrierst beim window-Objekt einen Event-Handler, der reagiert natürlich auf sämtliche dragover/drop-Ereignisse im gesamten Dokument. Das ist vermutlich nicht das, was du intendiert hast. Allerdings kann es durchaus einfacher sein, dokumentweite Event-Handler zu registrieren, anstatt die passenden Elemente mit Methoden wie getElementsByClassName herauszusuchen und vielen einzelnen Elementen Handler zu verpassen.

with ist für solche Zweck jedenfalls nicht gedacht. Wenn du eine HTMLCollection durchlaufen willst, dann kannst du das mit einer konventionellen for- oder while-Schleife tun:

var elements = document.getElementsByClassName("dropBox");  
for (var i = 0, element; element = elements[i]; i++) {  
   element.addEventListener("dragover", dragover, false);  
   element.addEventListener("drop", drop, false);  
}

Zum Nachlesen:
http://dmitrysoshnikov.com/ecmascript/chapter-2-variable-object/
http://dmitrysoshnikov.com/ecmascript/chapter-4-scope-chain/
</archiv/2010/2/t194977/#m1304595>

Mathias