Orlok: Javascript fehler

Beitrag lesen

Hallo mely

Du hast bei der Zuweisung die Klammern vergessen: $(target)$target

Ich bin noch nicht ganz gut in javascript und verstehe den Unterschied nicht.

Kein Problem.

Kannst du es bitte kurz erklären. Danke.

Ich kann es zumindest mal versuchen. :-)


Also, kurz gesagt, handelt es sich bei $(target) um den Aufruf einer Funktion namens $, bei welchem der Wert der zuvor definierten Variable mit dem Bezeichner target als Argument übergeben wird.

Die Angabe $target wiederum ist in diesem Zusammenhang der Versuch, über diesen Bezeichner eine zuvor nicht deklarierte Variable zu referenzieren.


Alles klar? Nein? – Ok.

Dann versuchen wir es lieber nochmal etwas ausführlicher! ;-)

Am besten schauen wir uns zunächst einmal den Teil deines Codes an um den es geht, und zwar in seiner ursprünglichen Form, bevor wir hier die in dieser Hinsicht relevanten Veränderungen vorgenommen haben:

$('nav a[href^="#"]').on('click', function (e) {
  e.preventDefault();

  // Die an dieser Stelle unwichtigen Anweisungen lasse ich mal weg…

  var target = this.hash;
  $target = $(target);

  $('html, body').stop().animate({
    'scrollTop' : $target.offset().top
  }, 500, 'swing', function () {
    window.location.hash = target;
    $(document).on('scroll', onScroll);
  });
});

Wie woodfighter bereits sagte, ist das Dollarzeichen, also $, kein Teil der Syntax von Javascript, sondern ein Bezeichner, also ein Name, über den jQuery angesprochen werden kann, also im Prinzip nichts anderes als wenn du selbst schreiben würdest:

function $ () {
  // irgendwelche Anweisungen
};

Das bedeutet, $() ist einfach nur der Aufruf einer Funktion. Wobei eine Funktion auch mit Argumenten aufgerufen werden kann, welche dann innerhalb der runden Klammern notiert werden, mit denen du dem Browser sagst, dass die Funktion aufgerufen werden soll.

Stellen wir uns nur so als Beispiel einmal vor, wir hätten eine Funktion mit zwei Parametern notiert, a und b, und dem Bezeichner add, dann könnte das so aussehen:

// Beispiel für Funktion mit Parametern

function add (a, b) {
  return a + b;
};

Diese Funktion könnten wir nun aufrufen, indem wir zunächst den Bezeichner der Funktion notieren, also den Namen add, den wir ihr gegeben haben, und danach ein paar runde Klammern, mit denen wir unseren Wunsch zum Ausdruck bringen, dass die Funktion jetzt aufgerufen werden soll.

Innerhalb dieser runden Klammern notieren wir nun durch Komma getrennt zwei Werte, das heißt, wir rufen die Funktion mit zwei Argumenten auf, und den Rückgabewert der Funktion, also das Ergebnis der Addition, die wir nach der return-Anweisung aufgeschrieben haben, speichern wir in einer Variable mit dem Bezeichner c:

// Beispiel für Funktionsaufruf mit Argumenten

var c = add(3, 5);

In der Variable mit dem Bezeichner c wäre nun also der Wert 8 gespeichert, da innerhalb unserer Funktion add die beiden Parameter mit den beim Aufruf der Funktion übergebenen Argumenten initialisiert werden, also a mit 3 und b mit 5.

Wenn wir nun also zu deinem Code zurückkommen, sehen wir, dass du innerhalb deiner anonymen, also namenlosen Funktion, die du der jQuery-Methode ‚on‘ als zweites Argument nach 'click' übergibst, die Anweisung var target = this.hash notiert hast.

Ohne an dieser Stelle zu weit abschweifen zu wollen sei gesagt, dass die Funktionsvariable this innerhalb dieser Funktion bei ihrem Aufruf mit dem Link initialisiert wird, auf den geklickt wurde, beziehungsweise mit dem Objekt, welches dieses Link-Element repräsentiert.

In der Variable mit dem Bezeichner target wird also der Wert der Objekteigenschaft hash hinterlegt, der hier identisch ist mit dem in deinem Markup angegebenen Wert des Attributes href. Also, um das nochmal zu verdeutlichen – du hast in deinem Markup folgenden internen Link…

<a href="#test1">Nav - Test 1</a>

…und über jQuery hast du nun eine Ereignisüberwachung für deine Links und den Ereignistyp ‚click‘ implementiert, das heißt, sollte jemand nun auf diesen Link klicken, dann würde in der Variable target der String '#test1' gespeichert werden. Und diesen String übergibst du nun jQuery, indem du schreibst…

$(target)

…damit jQuery dir anhand der ID das Element heraussucht, welches das Ziel (target) deines Links ist, und dir ein Objekt zurückgibt, auf welchem du von jQuery bereitgestellte Methoden anwenden kannst, wie beispielsweise offset(), welche selbst wiederum ein Objekt mit Eigenschaften wie etwa top zurückgibt, deren Wert in diesem Teil deines Codes dann zugewiesen wird (oder werden sollte):

'scrollTop' : $(target).offset().top

Du hast das mit den Objekten noch nicht so ganz verstanden?


Kein Problem. ;-)

Ein plain object, also ein ‚normales‘ Objekt wenn man so will, ist eine Datenstruktur, sprich es ist ein Container für Eigenschaften und Methoden, welcher aus Schlüssel/Wert-Paaren besteht, wobei von einer Methode gesprochen wird, wenn es sich bei dem Wert der Eigenschaft um eine Funktion handelt.

Es gibt nun verschiedene Möglichkeiten ein solches Objekt zu erzeugen, aber am besten sollte dies über die sogenannte Literalnotation geschehen:

var object = {
  property : 'value',
  method : function () {
    return this.property;
  }
};

Hier haben wir also zunächst einmal eine Variable mit dem Bezeichner object deklariert und diese zugleich auf definiert, indem wir ihr ein neu erstelltes Objekt als Wert zugewiesen haben.

Die Syntax zur Erzeugung eines Objektes besteht also darin, zwischen zwei geschweiften Klammern und durch Kommas getrennt die Eigenschaften aufzulisten, wobei der Bezeichner, also der Name der Eigenschaft zuerst notiert wird, dann ein Doppelpunkt, und dann der Wert, den die Eigenschaft haben soll.

In unserem Beispiel object haben wir nun zwei Eigenschaften hinterlegt, wobei eine davon als Wert eine Funktion hat, so dass wir hier von einer Methode sprechen. Innerhalb dieser Funktion verweist bei ihrem Aufruf die Variable this nun auf das Objekt selbst, so dass der Wert der ersten Eigenschaft mit den Namen property zurückgegeben wird, also der String 'value'.

Wenn man also ein Objekt erstellt hat, dann gibt es zwei Wege, um auf dessen Eigenschaften zuzugreifen, nämlich entweder über die Punktnotation oder über die Klammernotation:

var myValue = object.property;

// ist also das gleiche wie:

var myValue = object['property'];

In beiden Fällen wäre nun der Wert der Eigenschaft property in der Variable mit dem Bezeichner myValue hinterlegt. Aber, auch wenn beide Varianten funktionieren, sollte der besseren Lesbarkeit wegen wenn möglich die Punktnotation verwendet werden. ;-)

Jedenfalls kann ein Objekt natürlich nicht nur als Wert einer Variable hinterlegt werden, sondern es kann auch direkt beim Aufruf einer Funktion notiert werden, wie zum Beispiel bei folgendem Methodenaufruf, den ich mal deiner Datei script.js entnommen habe:

$(".zoom-demo").spritezoom({
  fadeInSpeed : 200,
  fadeOutSpeed : 100,
  behavior : "hover",
  layout : "magnify",
  border : 4,
  magSize : 0.8
}); 

Das ist eine sehr nützliche Möglichkeit, um einer Funktion bei ihrem Aufruf Werte mitzugeben, insbesondere dann, wenn sehr viele Parameter benötigt werden, denn sonst müsste man sich immer die genaue Reihenfolge merken, in der die Argumente zu übergeben sind. So übergibt man nur ein Objekt, also ein Argument, und innerhalb der Funktion können dann die einzelnen Eigenschaftswerte ausgelesen werden.

Andersherum kann ein Objekt natürlich auch der Rückgabewert einer Funktion sein, was zum Beispiel so umgesetzt werden kann:

var getObject = function () {
  return {
    a : 1,
    b : 2,
    c : 3
  };
};

Dabei ist allerdings zu beachten, dass die öffnende geschweifte Klammer für das Objekt in der selben Zeile wie die return-Anweisung stehen muss, da sonst durch die automatische Einfügung eines Semikolons die Ausführung der Funktion nach dieser Anweisung abgebrochen würde und der Code mit dem Objekt nicht mehr erreicht würde.

Das nur nebenbei bemerkt. ;-)


Aber kommen wir wieder zurück zu deinem ursprünglichen Code:

  // ...
  $target = $(target);
  // ...
  'scrollTop' : $target.offset().top
  // ...

Das war die Stelle, an der ich dir empfohlen hatte, die Variablenzuweisung zu löschen und statt dessen den Funktionsaufruf direkt bei der Zuweisung zu notieren, da du hier nicht nur eine globale Variable produziert hast, sondern darüber hinaus an diesem Punkt eigentlich überhaupt keine Variablendefinition notwendig war. Denn du verwendest den entsprechenden Rückgabewert von $(target) ja ohnehin nur einmal, nämlich bei eben jener Zuweisung ein paar Zeilen weiter.

Nun hattest du zwar die Zeile $target = $(target); wie angeraten gelöscht, aber eben vergessen, bei der Wertzuweisung weiter unten $target durch $(target) zu ersetzen, mit der Folge, dass dir dein Script beim Klick auf einen Link mit einen Reference Error um die Ohren geflogen ist, da nach der Löschung natürlich keine Variable mit dem Bezeichner $target mehr vorhanden war.

Du möchtest nun vielleicht etwas genauer wissen, warum ich dir das empfohlen habe?

Ok. :-)

Ich nehme an, du hast sicherlich verstanden, dass es nicht besonders sinnvoll ist, einen Wert extra in einer Variablen zu hinterlegen, wenn man ihn ohnehin nur an einer einzigen Stelle benötigt, aber zur Verdeutlichung vielleicht nochmal ein kleines Beispiel:

var $target = $(target);
var offset = $target.offset();
var top = offset.top;
// ...
'scrollTop' : top

Theoretisch hättest du das ganze auch so notieren können, also zunächst einmal den Rückgabewert von $(target) in der Variable mit dem Bezeichner $target speichern, dann auf diesem Objekt die Methode offset() aufrufen und deren Rückgabewert in einer Variable mit dem Bezeichner offset hinterlegen, um dann schließlich von diesem Objekt die Eigenschaft top auszulesen, deren Wert dann wiederum einer dritten Variablen zugewiesen wird, also top.

Ziemlich umständlich oder?

'scrollTop' : $(target).offset().top

…ist da doch offensichtlich die deutlich elegantere Schreibweise, würde ich meinen. ;-)

Naja, und dann ist da natürlich noch die Sache mit der globalen Variable.

Zur Erinnerung, du hattest geschrieben:

$target = $(target);

Du hast hier also eine Variable erzeugt, ohne das Keyword var zu verwenden, sondern einfach nur, indem du einen Bezeichner, also einen Namen notiert und dann einen Wert zugewiesen hast. Und das ist schlecht. Denn auf diese Weise wird die Variable auch außerhalb deiner Funktion, also überall in deinem Script „sichtbar“ und kann entsprechend überschrieben werden beziehungsweise eine andere globale Variable mit demselben Bezeichner überschreiben!


Also das war jetzt eine Menge Information, aber keine Sorge, wenn du nicht alles direkt verstanden hast! Jedenfalls, wenn du JavaScript lernen willst, würde ich empfehlen, einfach mal ins SELFHTML-Wiki zu schauen. :-)

Viele Grüße,

Orlok