Dinge genutzt wird. In der objektorientierten JavaScript-Programmierung wird
this
in den Methoden eines Objekts genutzt, um sich auf dieses Objekt zu beziehen – so wie
self
in Python oder Ruby:
function Foo( value ) {
this.value = value;
}
Foo.prototype.alert = function() {
alert( this.value );
};
var foo = new Foo( 'bar' );
foo.alert(); // 'bar'
Im Code für ein klassisches
on
event
-Attribut bezieht sich
this
auf das Element, das das Event erhält – aber nur im Attribut selbst, nicht in einer Funktion, die vom Attribut aufgerufen wird:
Testfunction clicked( it ) {
alert( it.id ); // 'test'
alert( this.id ); // undefined
alert( this === window ); // true (was?)
}
Wie Sie am dritten
alert()
sehen können, ist
this
innerhalb der Funktion tatsächlich das
window
-Objekt. Aus historischen Gründen ist
window
der »Standard«-Wert von
this
, wenn eine Funktion direkt aufgerufen wird (also nicht als Methode eines Objekts).
In einem jQuery-Eventhandler ist
this
das DOM-Element, das das Event behandelt, daher ist
$(this)
ein jQuery-Wrapper für das DOM-Element. Aus diesem Grund funktioniert
$(this).addClass()
in unserem »problematischen« Code auch wie erwartet.
Aber der Code ruft dann
setTimeout()
auf und
setTimeout()
verhält sich wie ein direkter Funktionsaufruf:
this
ist das Objekt
window
. Ruft der Code also
$(this).removeClass()
auf, wird tatsächlich versucht, die Klasse dem
window
-Objekt zu entziehen!
Warum hilft es dann,
this
oder
$(this)
in eine lokale Variable zu kopieren? JavaScript erstellt ein Closure für die Parameter und lokalen Variablen einer Funktion.
Closures mögen zuerst ein wenig mysteriös erscheinen, aber sie lassen sich wirklich mit drei einfachen Regeln beschreiben:
Sie können JavaScript-Funktionen beliebig ineinander verschachteln.
Eine Funktion kann nicht nur ihre eigenen Parameter und lokalen Variablen lesen und schreiben, sondern auch die jeder Funktion, in der sie eingebettet ist.
Die vorige Regel gilt immer , auch wenn die äußere Funktion schon zurückgesprungen ist und die innere Funktion erst später aufgerufen wird (zum Beispiel ein Eventhandler oder ein
setTimeout()
-Callback).
Diese Regeln gelten für alle Funktionen – sowohl für benannte als auch für anonyme Funktionen. Allerdings ist
this
kein Funktionsparameter und auch keine lokale Variable, sondern ein spezielles JavaScript-Schlüsselwort, daher finden diese Regeln hier keine Anwendung. Kopiert man den Wert von
this
in eine lokale Variable, dann kann man die Vorteile des Closures nutzen und den Wert in jeder verschachtelten Funktion nutzen.
Überflüssige Wiederholungen vermeiden
Problem
Sie wollen ein paar DOM-Elemente beim Laden der Seite verbergen, anzeigen oder anders bearbeiten und dies auch zu einem späteren Zeitpunkt als Reaktion auf bestimmte Events wiederholen:
$(document).ready( function() {
// Sichtbarkeit beim Starten setzen
$('#state').toggle( $('#country').val() == 'US' );
$('#province').toggle( $('#country').val() == 'CA' );
// Sichtbarkeit ändern, wenn der Wert per Maus geändert wird
$('#country').change( function() {
$('#state').toggle( $(this).val() == 'US' );
$('#province').toggle( $(this).val() == 'CA' );
});
// Sichtbarkeit auch ändern, wenn der Wert per Tastatur geändert wird
$('#country').keyup( function() {
$('#state').toggle( $(this).val() == 'US' );
$('#province').toggle( $(this).val() == 'CA' );
});
});
Der Code funktioniert, aber Sie wollen ihn vereinfachen, so dass es nicht so viel doppelten Code gibt.
----
Note
Warum nutzen wir sowohl das
change
- als auch das
keyup
-Event? Viele Websites kümmern sich bei einer Auswahlliste nur um das
change
-Event. Das funktioniert prima, wenn Sie mit der Maus eine Auswahl treffen. Wenn Sie aber in die Liste klicken und dann die Pfeiltasten nutzen, um eine der Optionen auszuwählen, passiert nichts – Tastenbetätigungen feuern in einer Auswahlliste keine
change
-Events. Kümmern Sie sich auch um das
keyup
-Event, dann reagiert die Auswahlliste auch auf die Pfeiltasten und hilft damit Anwendern, die mit der Tastatur arbeiten (müssen).
----
Lösung 1
Verschieben Sie den doppelten Code in eine Funktion und rufen Sie diese sowohl beim Laden der Webseite als auch als Reaktion auf die Events auf. Mit der jQuery-Methode
.bind()
verbindenSie beide Eventhandler gleichzeitig. Und speichern Sie Daten, die mehr als einmal genutzt werden, in