addEventListener ohne Parameterübergabe

Ich muss mich bei den JavaScript-Kundigen meiner Leserschaft ein bisschen ausweinen. Sorry. Aber ich kann mir eine ganz bestimmte Sache nicht erklären.

Folgendes: Ich schreibe ein Script, das bei Aufruf der Seite den DOM-Baum analysiert und ganz bestimmten <li>-Elementen einen EventHandler zuweist. Das klappt soweit auch ganz hervorragend und natürlich unterscheide ich hier zwischen guten und bösen Browsern – jeder kriegt sein bevorzugtes Codefragment, mit dem ich ein onclick dort anbringe, wo vorher kein onclick gewesen ist:

meinListItem.addEventListener("click", macheEtwas, false);

} else if (meinListItem.attachEvent) { //Explorer
meinListItem.attachEvent("onclick", macheEtwas);

} else {
meinListItem.onclick = macheEtwas;

}



Nun meine superintelligente Frage: Warum zur Hölle kann ich meiner Funktion macheEtwas eigentlich keine Parameter übergeben? Es ist offensichtlich nicht vorgesehen, und das macht mich fuchsig. Denn ohne Parameterübergabe machen Funktionen doch nur halb so viel Spaß! Hier leistet sich JavaScript eine Inkonsistenz, die ich nicht verstehe. Vielleicht muss mir da jemand auf die Sprünge helfen!

6 Kommentare

Thomas Alexnat

Bei der Funktion ›macheEtwas‹ fehlen die Klammern ‹()‹ zum Kennzeichnen einer Methode. Korrekt muss es lauten:
meinListItem.onclick = macheEtwas();
Die anderen Codezeilen entsprechend ergänzen.

..

http://www.svendtofte.com/code/curried_javascript/
Es gibt noch Besseres dazu, was ich aber gerade nicht finde. Die Zauberwörter sind »Lambda-Funktion« und »verzögerte Funktion«.

molily

Siehe auch Closure.
Man notiert eine Funktion, die als Closure wirkt, das heißt, im Scope dieser Funktion sind alle Variablen des Scopes verfügbar, in dem die Funktion notiert wurde.
var variable = "bla";
function closure (evt) {
// hier ist variable verfuegbar
macheEtwas(evt, variable);
}
element.addEventListener("click", closure, false);
function macheEtwas (evt, parameter) {
alert(parameter);
}
Das Ganze kann auch in einer Funktion ablaufen, variable muss also keine globale Variable sein.
Die Closure kann man auch als Function-Expression, also als anonyme Funktion, notieren:
element.addEventListener("click", function (evt) { alert(variable); }, false);
Alternativ kann man die »Parameter« einfach am Elementknoten speichern und mit evt.target.eigenschaft in der Handler-Funktion darauf zugreifen. (Bei Microsofts attachEvent ist nicht unbedingt das li-Element das target, siehe The difference between addEventListener and attachEvent. Im MSIE kann man nur mit dem traditionellen Modell auf das Zielelement zugreifen, bei dem der Event-Handler registriert wurde.)
Thomas’ Kommentar ist übrigens falsch – die Funktion soll nicht schon beim Registrieren (= Kopieren in die Eigenschaft onclick) ausgeführt werden.
Im Übrigen ist die Abfrage W3C DOM Events > Microsoft attachEvent > traditionelles Modell nicht sonderlich sinnig. Wenn man mehrere Handler registrieren will, geht das so nicht abwärtskompatibel. Daher müsste man Browser, die weder addEventListener noch attachEvent kennen, ausschließen, oder man nimmt eine neue addEvent-Funktion.

bjoern

Als Ergänzung möchte ich Dir für solche Sachen die Kombination aus:
=> Behaviour
… und einer addEvent-Function von John Resig (der beim quirksmode.org-addEvent-Recoding-Contest gewonnen hat) empfehlen darf:
=> Flexible Javascript Events
Mit ersterem kannst Du mithilfe von CSS-Definitionen bestimmten Elementen bestimmte Eigenschaften oder »Verhalten« beibringen. Gerade mit AJAX und massivem Einsatz von JavaScript zur Ergänzung der GUI-Funktionen kann man so sehr schön »zaubern«.
Und mit letzterem benutzt Du eine sehr schöne Funktion, mit der Du einem Element auch mehrere Verhalten von mehreren Stellen aus zuweisen kannst, ohne Dich darum kümmern zu müssen, dass man jetzt nicht aus Versehen ein bestehendes Event überschreibt.
Von Dean Edwards (der »Erfinder« von IE7) gibt es noch eine sehr interessante Library namens cssQuery(). Auch ganz nett.
Meiner Meinung nach mit der Kombination aus Script.aculo.us und Prototype ein unverzichtbares Team für ansprechende Frontend-Entwicklungen und Web-Applikations-Design.

Markus Stange

Macht es eigentlich Sinn, die erweiterten Event-Modelle zu nutzen, wenn man nur einen Handler braucht? In diesem Fall sieht es so aus, als wäre die ganze Sache mit den Eventmodell-Überprüfungen nicht nötig.

Gerrit

Ich brauche keine umfangreichen Bibliotheken, da es letztlich nur um eine billige Ausklappnavigation geht. Jedoch habe ich den Anspruch, diese Navigation komplett ohne zusätzlichen HTML-Code und ohne Zuweisung von IDs hinzubekommen. Wie gesagt, es klappt alles, bis auf die Übergaben der Variable. Aber dank molily habe ich jetzt zwei mögliche Lösungswege:
1) Meine Zielfunktion direkt im addEventListener-Aufruf zu definieren
2) Über das aufrufende Element mir die Infos zu holen.
Ich werde das probieren. Und vielen Dank an alle!

Kommentar verfassen