Ergebnis 1 bis 16 von 16

Javascript Variablen in anonymer Funktion

  1. #1 Zitieren
    Ritter Avatar von Feuerstern
    Registriert seit
    Sep 2007
    Beiträge
    1.823
    Hallo Leute,
    ich versuche in Javascript mehreren Buttons eine Funktion zu übergeben die beim anklicken ausgeführt werden soll.
    Dafür verwende ich eine anonyme Funktion die durch eine Schleife jedem Button zugeordnet werden soll.
    Das Array "btns" besitzt in meinem Beispiel 3 Elemente.
    In der anonymen Funktion brauche ich allerdings den index des im Array gespeicherten Buttons.
    Das Problem ist nun das die Variable "index" in der Funktion immer 2 ist (da index zuletzt der Wert 2 zugeordnet wird).
    Verzichte ich auf die zwischen Variable "index" und verwende sofort "i" ist sie 3 weil sie in der Schleife bis 3 hochgezählt wird.
    Wie komme ich in der annonymen Funktion an den Wert von "i" den die Variable zum Zeitpunkt der Zuweisung der anonymen Funktion besitzt?

    Code:
    var isElementClicked = [];
    var btns = document.getElementsByClassName("colorButton");
    for (i = 0; i != btns.length; i++)
    {
    	var index = i;
    	isElementClicked.push(false);
    	var btn = btns[i];
    	btn.style.cursor = "pointer";
    	btn.onclick = function() 
    	{
    		
    		var color = $(this).css("backgroundColor");		
    		var lineMenu = document.getElementById("linemenu");
    		lineMenu.style.borderColor = color;
    		isElementClicked[index] = !isElementClicked[index];
    		
    	}		
    }
    Feuerstern ist offline Geändert von Feuerstern (03.11.2015 um 09:25 Uhr)

  2. #2 Zitieren
    Retro Micky Avatar von Blue Force
    Registriert seit
    May 2009
    Beiträge
    26.200
    ich verstehe nicht warum index in der Funktion immer 2 sein soll, bzw. i immer 3.
    die Funktion wird doch innerhalb der Schleife aufgerufen, D.h. beim ersten Durchlauf ist i=0 und auch index=0, und so weiter, oder habe ich da was übersehen?
    Vielleicht kannst du auch i oder index als Parameter an die Funktion übergeben?
    1 2 3 4 5
    Blue Force ist offline Geändert von Blue Force (02.11.2015 um 22:51 Uhr)

  3. #3 Zitieren
    Knight Commander Avatar von Kellendil
    Registriert seit
    Jul 2009
    Beiträge
    2.101
    Du könntest für jedes binding ne eigene closure erstellen also

    onclick = function(index) {
    return function() {

    //...
    //... isElementClicked[index] ...

    }
    }(i);
    Kellendil ist offline

  4. #4 Zitieren
    Tieftöner Avatar von Lookbehind
    Registriert seit
    Dec 2007
    Beiträge
    15.176
    Die schleife wird übrigens sehr früh abgebrochen...
    Abbruch-Bedingung: i != btns.length
    Solange btns nicht leer ist, wird sie nicht einmal ausgeführt.
    Du möchtest das "ungleich" vielleicht durch ein "kleiner als" ersetzen.
    Lookbehind ist offline

  5. #5 Zitieren
    Held Avatar von Satans Krümelmonster
    Registriert seit
    Aug 2007
    Beiträge
    5.797
    Wenn du eh jQuery geladen hast, würde ich es einfach so machen:

    Code:
    var lineMenu = $('#linemenu');
    
    $('.colorButton').click(function() {
    	var t = $(this);
    	
    	lineMenu.css('border-color', t.css('background-color'));
    	
    	t.data('clicked', !t.data('clicked'));
    }).data('clicked', false).css('cursor', 'pointer');
    Und wenn du dann wissen willst, ob der Button geklickt wurde, rufst du $(button).data('clicked'); auf.
    Satans Krümelmonster ist offline

  6. #6 Zitieren
    Legende Avatar von jabu
    Registriert seit
    Jul 2011
    Beiträge
    7.383
    Zitat Zitat von Lookbehind Beitrag anzeigen
    Die schleife wird übrigens sehr früh abgebrochen...
    Abbruch-Bedingung: i != btns.length
    Solange btns nicht leer ist, wird sie nicht einmal ausgeführt.
    Du möchtest das "ungleich" vielleicht durch ein "kleiner als" ersetzen.
    Der nächste, der nur gucken will, ob ich was übersehe...
    Die Schleife wird ausgeführt, wenn die Bedingung wahr ist. Also ist das schon so in Ordnung. Dein Vorschlag funktioniert natürlich auch, ist aber nicht nötig.

    Zitat Zitat von Feuerstern Beitrag anzeigen
    Hallo Leute,
    ich versuche in Javascript mehreren Buttons eine Funktion zu übergeben die beim anklicken ausgeführt werden soll.
    Dafür verwende ich eine anonyme Funktion die durch eine Schleife jedem Button zugeordnet werden soll.
    Man versteht dich ziemlich schlecht. Ist das so gemeint?

    Das Array "btns" besitzt in meinem Beispiel 3 Elemente.
    In der anonymen Funktion brauche ich allerdings den index des im Array gespeicherten Buttons.
    Das Problem ist nun das die Variable "index" in der Funktion immer 2 ist (da index zuletzt der Wert 2 zugeordnet wird).
    Verzichte ich auf die zwischen Variable "index" und verwende sofort "i" ist sie 3 weil sie in der Schleife bis 3 hochgezählt wird.
    Das Verhalten ist korrekt, wie du es beschreibst, wenn die Funktion außerhalb der Schleife aufgerufen wird. Innerhalb der Schleife erhält sie zwar ihren Kontext, aber die Werte sind diejenigen zum Zeitpunkt des Aufrufs. So, wie du es schilderst, ist die Schleife dann schon durchgelaufen, was eben zu den beobachteten Werten führt.

    Wie komme ich in der annonymen Funktion an den Wert von "i" den die Variable zum Zeitpunkt der Zuweisung der anonymen Funktion besitzt?
    So einfach gar nicht, weil nicht die Funktion zugewiesen wird, sondern ein Verweis auf diese. Du rufst sie vermutlich irgendwo auf (fehlt hier Edit: Nein, es fehlt nicht, denn ich hatte den "onclick Event" nicht identifiziert), wobei der aktuelle Kontext gilt. Das ist innerhalb der Schleife der ihres letzten Durchlaufs, wenn die Werte nicht anderweitig geändert worden sind.
    Edit: Inzwischen sehe ich auch, dass dir das längst klar gewesen ist.

    Falls ich Blödsinn geschrieben habe, bitte korrigieren. Mache normalerweise nichts mit JavaScript.

    Edit: Da haben wir es schon: Vergiss, was ich über die passende Abstraktion geschrieben hatte, mit Closures geht es nicht nur, sondern die Abstraktion stimmt auch.
    jabu ist offline Geändert von jabu (04.11.2015 um 00:50 Uhr)

  7. #7 Zitieren
    Ritter Avatar von Feuerstern
    Registriert seit
    Sep 2007
    Beiträge
    1.823
    Erstmal danke für eure schnellen Antworten.

    Zitat Zitat von Blue Force Beitrag anzeigen
    ich verstehe nicht warum index in der Funktion immer 2 sein soll, bzw. i immer 3.
    die Funktion wird doch innerhalb der Schleife aufgerufen, D.h. beim ersten Durchlauf ist i=0 und auch index=0, und so weiter, oder habe ich da was übersehen?
    Vielleicht kannst du auch "i" oder index als Parameter an die Funktion übergeben?
    Das ist richtig. Deshalb verstehe ich auch nicht wieso "i" in der Funktion immer den Wert besitzt den es nach dem hochzählen hat. In anderen mir bekannten Sprachen hatte ich das Problem auch nie.

    Zitat Zitat von Kellendil Beitrag anzeigen
    Du könntest für jedes binding ne eigene closure erstellen also

    onclick = function(index) {
    return function() {

    //...
    //... isElementClicked[index] ...

    }
    }(i);
    Das werde ich nachher mal ausprobieren.

    Zitat Zitat von Lookbehind Beitrag anzeigen
    Die schleife wird übrigens sehr früh abgebrochen...
    Abbruch-Bedingung: i != btns.length
    Solange btns nicht leer ist, wird sie nicht einmal ausgeführt.
    Du möchtest das "ungleich" vielleicht durch ein "kleiner als" ersetzen.
    Das Array btns enthält 3 Elemente und ich möchte Element 0, 1 und 2 mit != btn.length (in diesem Fall 3) müsste die Bedingung doch erfüllt sein.
    Kleiner als hätte doch den gleichen Effekt oder übersehe ich da etwas?

    Zitat Zitat von Satans Krümelmonster Beitrag anzeigen
    Wenn du eh jQuery geladen hast, würde ich es einfach so machen:

    Code:
    var lineMenu = $('#linemenu');
    
    $('.colorButton').click(function() {
    	var t = $(this);
    	
    	lineMenu.css('border-color', t.css('background-color'));
    	
    	t.data('clicked', !t.data('clicked'));
    }).data('clicked', false).css('cursor', 'pointer');
    Und wenn du dann wissen willst, ob der Button geklickt wurde, rufst du $(button).data('clicked'); auf.
    Dann müsste ich das ganze aber für jeden Button einzeln machen oder?
    Das wollte ich eigentlich vermeiden da in Zukunft vlt noch Buttons dazu kommen.

    Edit:
    Zitat Zitat von jabu Beitrag anzeigen
    Man versteht dich ziemlich schlecht. Ist das so gemeint?
    Ja genau, war schon was später gestern.

    Zitat Zitat von jabu Beitrag anzeigen
    Gar nicht, weil nicht die Funktion zugewiesen wird, sondern ein Verweis auf diese. Du rufst sie vermutlich irgendwo auf (fehlt hier), wobei der aktuelle Kontext gilt. Das ist innerhalb der Schleife der ihres letzten Durchlaufs, wenn die Werte nicht anderweitig geändert worden sind.

    Du könntest natürlich dein Array mit den entsprechenden Daten innerhalb der Schleife auffüllen, wenn es dir darum geht. Das müsstest du dann außerhalb des Funktionsaufrufs tun.
    Wenn du deine Funktion innerhalb der Schleife aufrufen willst, so fehlt einfach der Aufruf an diese.
    Wenn die Funktion mit aktuellen Daten aufgerufen werden soll, dann empfiehlt es sich, ihr aktuelle Parameter zu übergeben.
    Ich weiß ja nicht, was du vor hast.

    Ganz grundsätzlich bezweifle ich, dass deine Abstraktion auf das Problem passt. Dort erst mal anzusetzen und einmal gründlich für dich selbst das Problem zu beschreiben, bevor du programmierst, könnte helfen.

    Falls ich Blödsinn geschrieben habe, bitte korrigieren. Mache normalerweise nichts mit JavaScript.
    Ich habe auf der Seite 3 Buttons (welche eig. anklickbare div Blöcke sind) die nach dem anklicken dem Element "lineMenu" diese Farbe zuweißen.
    Das Funktioniert auch soweit. Jetzt möchte ich aber noch feststellen ob ein Button gedrückt wurde, um dan sein Design anzupassen, so das man sieht das er gedrückt ist und beim erneuten drücken das Design wieder zurückzusetzten. Dafür die Zeile:
    Code:
    isElementClicked[index] = !isElementClicked[index];
    Feuerstern ist offline Geändert von Feuerstern (03.11.2015 um 09:43 Uhr)

  8. #8 Zitieren
    Held Avatar von Satans Krümelmonster
    Registriert seit
    Aug 2007
    Beiträge
    5.797
    Zitat Zitat von Feuerstern Beitrag anzeigen
    Dann müsste ich das ganze aber für jeden Button einzeln machen oder?
    Das wollte ich eigentlich vermeiden da in Zukunft vlt noch Buttons dazu kommen.
    Nein. Der Aufruf $('.colorButton') sucht alle Elemente mit der Klasse colorButton raus. Eben genau das, was deine Funktion document.getElementsByClassName macht.

    Das prinzipielle Problem ist hier übrigens, dass du index in jedem Schleifenaufruf überschreibst. Erst ist es 1, dann 2 und dann 3. Wird jetzt der Button geklickt (dies geschieht ja nachdem die Schleife komplett abgearbeitet wurde), dann ist index = 2, das hast du ja in der Schleife überschieben. Hier merkt sich Javascript nicht, was der Index zur Zeit der Erstellung ist, sondern was er zur Zeit der Ausführung ist.

    Mit der Lösung von Kellendil kann man sehr elegant umgehen: Man definiert eine Funktion, die die onClick-Funktion wiederum zurückgibt. Und diese ruft man dann direkt auf.
    In dem Fall ist index (was ja jetzt der Parameter der äußeren Funktion ist), unabhängig definiert. Eine Änderung von i ändert index nicht, weil die äußere Funktion ja nicht noch einmal ausgeführt wird.
    Satans Krümelmonster ist offline

  9. #9 Zitieren
    Tieftöner Avatar von Lookbehind
    Registriert seit
    Dec 2007
    Beiträge
    15.176
    Zitat Zitat von jabu Beitrag anzeigen
    Der nächste, der nur gucken will, ob ich was übersehe...
    Die Schleife wird ausgeführt, wenn die Bedingung wahr ist. Also ist das schon so in Ordnung. Dein Vorschlag funktioniert natürlich auch, ist aber nicht nötig.
    ...
    Zitat Zitat von Feuerstern Beitrag anzeigen
    ...
    Das Array btns enthält 3 Elemente und ich möchte Element 0, 1 und 2 mit != btn.length (in diesem Fall 3) müsste die Bedingung doch erfüllt sein.
    Kleiner als hätte doch den gleichen Effekt oder übersehe ich da etwas?
    ...
    Es war spät... Scheinbar zu spät.
    Lookbehind ist offline

  10. #10 Zitieren
    Ritter Avatar von Feuerstern
    Registriert seit
    Sep 2007
    Beiträge
    1.823
    Zitat Zitat von Kellendil Beitrag anzeigen
    Du könntest für jedes binding ne eigene closure erstellen also

    onclick = function(index) {
    return function() {

    //...
    //... isElementClicked[index] ...

    }
    }(i);
    Zitat Zitat von Satans Krümelmonster Beitrag anzeigen
    Nein. Der Aufruf $('.colorButton') sucht alle Elemente mit der Klasse colorButton raus. Eben genau das, was deine Funktion document.getElementsByClassName macht.

    Das prinzipielle Problem ist hier übrigens, dass du index in jedem Schleifenaufruf überschreibst. Erst ist es 1, dann 2 und dann 3. Wird jetzt der Button geklickt (dies geschieht ja nachdem die Schleife komplett abgearbeitet wurde), dann ist index = 2, das hast du ja in der Schleife überschieben. Hier merkt sich Javascript nicht, was der Index zur Zeit der Erstellung ist, sondern was er zur Zeit der Ausführung ist.

    Mit der Lösung von Kellendil kann man sehr elegant umgehen: Man definiert eine Funktion, die die onClick-Funktion wiederum zurückgibt. Und diese ruft man dann direkt auf.
    In dem Fall ist index (was ja jetzt der Parameter der äußeren Funktion ist), unabhängig definiert. Eine Änderung von i ändert index nicht, weil die äußere Funktion ja nicht noch einmal ausgeführt wird.
    Hat wunderbar funktioniert. Danke an alle für die Hilfe und die ausführlichen Erläuterungen.

    Noch eine kleine Frage am Rande:
    Lohnt es sich von vorne herein mit jQuery zu arbeiten?
    Vieles scheint mir wesentlich eleganter mit jQuery zu sein.
    Feuerstern ist offline

  11. #11 Zitieren
    Legende Avatar von jabu
    Registriert seit
    Jul 2011
    Beiträge
    7.383
    Zitat Zitat von Lookbehind Beitrag anzeigen
    Es war spät... Scheinbar zu spät.
    Und ich hatte übersehen, dass der Aufruf über einen "onclick Event" erfolgt. Dann ist es logisch, dass man so etwas wie Funktionsobjekte haben will, funktionale Programmierung, wtf. Dann passt auch die Abstraktion. Habe meinen letzten Beitrag dementsprechend editiert.
    jabu ist offline

  12. #12 Zitieren
    Held Avatar von Satans Krümelmonster
    Registriert seit
    Aug 2007
    Beiträge
    5.797
    Zitat Zitat von Feuerstern Beitrag anzeigen
    Lohnt es sich von vorne herein mit jQuery zu arbeiten?
    Vieles scheint mir wesentlich eleganter mit jQuery zu sein.
    Wenn du wirklich Javascript lernen willst, ist es vielleicht von Vorteil erstmal ohne jQuery zu starten. Dann lernt man mehr darüber, wie diese Sprache funktioniert, denke ich.
    Aber wie du schon sagtest, es ist einfach eleganter und man muss sich nicht so viele Gedanken über Cross-Browser-Compability machen.
    Satans Krümelmonster ist offline

  13. #13 Zitieren
    Knight Commander Avatar von Kellendil
    Registriert seit
    Jul 2009
    Beiträge
    2.101
    Javascript wird immer mal wieder WTFs produzieren, liegt wohl an der Inkonsistenz der Sprache.
    Kurze Erkläsrung
    Die Lösung von mir bewirkt, dass jeder i-Wert (zum Zeitpunkt der unterschiedlichen Werte) irgendwie innerhalb einer Funktion vorkommt (wie man das anstellt ist relativ egal). Alles was in einer Funktion vorkommt hat einen eigenen Scope und damit bleiben die Werte erhalten für jede Funktion, und können später von den zurückgegebenen Funktion referenziert werden (closure).
    Ich persönlich würde, sobald es etwas komplexer wird, auf jQuery umsteigen, inbesondere wenn man eher produktiv sein will statt zu lernen. Und ich würde stark empfehlen (finde ich am wichtigsten), das gesamte Javascript in Modulform zu erstellen (keine globaler Code! Zusammenhängender Code (=Modul) wird in eine Funktion getan und ist damit nicht mehr global). Das erspart dir später langwieriges redactoring und Aufräumen von Dependencies, wenn man z.B. Precompiler wie Browserify benutzt, um "echte" Module zu schreiben.
    Und: EventHandling nicht im HTML! Ist am Anfang relativ egal, aberwenns größer wird, wird das wichtig.
    Kellendil ist offline Geändert von Kellendil (04.11.2015 um 08:30 Uhr)

  14. #14 Zitieren
    Ritter Avatar von Feuerstern
    Registriert seit
    Sep 2007
    Beiträge
    1.823
    Zitat Zitat von Satans Krümelmonster Beitrag anzeigen
    Wenn du wirklich Javascript lernen willst, ist es vielleicht von Vorteil erstmal ohne jQuery zu starten. Dann lernt man mehr darüber, wie diese Sprache funktioniert, denke ich.
    Aber wie du schon sagtest, es ist einfach eleganter und man muss sich nicht so viele Gedanken über Cross-Browser-Compability machen.

    Zitat Zitat von Kellendil Beitrag anzeigen
    Javascript wird immer mal wieder WTFs produzieren, liegt wohl an der Inkonsistenz der Sprache.
    Kurze Erkläsrung
    Die Lösung von mir bewirkt, dass jeder i-Wert (zum Zeitpunkt der unterschiedlichen Werte) irgendwie innerhalb einer Funktion vorkommt (wie man das anstellt ist relativ egal). Alles was in einer Funktion vorkommt hat einen eigenen Scope und damit bleiben die Werte erhalten für jede Funktion, und können später von den zurückgegebenen Funktion referenziert werden (closure).
    Ich persönlich würde, sobald es etwas komplexer wird, auf jQuery umsteigen, inbesondere wenn man eher produktiv sein will statt zu lernen. Und ich würde stark empfehlen (finde ich am wichtigsten), das gesamte Javascript in Modulform zu erstellen (keine globaler Code! Zusammenhängender Code (=Modul) wird in eine Funktion getan und ist damit nicht mehr global). Das erspart dir später langwieriges redactoring und Aufräumen von Dependencies, wenn man z.B. Precompiler wie Browserify benutzt, um "echte" Module zu schreiben.
    Und: EventHandling nicht im HTML! Ist am Anfang relativ egal, aberwenns größer wird, wird das wichtig.
    Danke für eure Antworten. Bei den Anwendugsfällen von javascript geht es mir mehr um die Ergebnisse und effizent ans Ziel zu kommen, denke dan ist jQuery die richtige Wahl. Scheint ja im Internet, so wie es aussieht, sowieso schon fast der Standart zu sein.
    Wie meinst du das mit dem EventHandling? Eine Funktion in einer externen Datei erstellen, die als Parameter das Objekt entgegen nimmt auf dem das Event angewendet werden soll?
    Feuerstern ist offline

  15. #15 Zitieren
    Held Avatar von Satans Krümelmonster
    Registriert seit
    Aug 2007
    Beiträge
    5.797
    Zitat Zitat von Feuerstern Beitrag anzeigen
    Wie meinst du das mit dem EventHandling? Eine Funktion in einer externen Datei erstellen, die als Parameter das Objekt entgegen nimmt auf dem das Event angewendet werden soll?
    Du bindest das click-Event mit element.onclick an das Element. Damit greifst du auf das onclick-Attribut im HTML-DOM zu. Das solltest du aber nicht machen, weil man durch einfaches Überschreiben des Attributes das Binding wieder aufheben kann.
    Wenn du element.addEventListener('click', function() {...}); (oder mit jQuery $(element).on('click', function() {...});) benutzt, dann ist es nicht so einfach den Listener zu überschreiben. Und es besteht auch nicht die Gefahr, dass du versehentlich bereits definierte Listener überschreibst.
    Satans Krümelmonster ist offline

  16. #16 Zitieren
    Knight Commander Avatar von Kellendil
    Registriert seit
    Jul 2009
    Beiträge
    2.101
    Zitat Zitat von Satans Krümelmonster Beitrag anzeigen
    Du bindest das click-Event mit element.onclick an das Element. Damit greifst du auf das onclick-Attribut im HTML-DOM zu. Das solltest du aber nicht machen, weil man durch einfaches Überschreiben des Attributes das Binding wieder aufheben kann.
    Das wusste ich gar nicht, ist sicher ein guter Rat. Dann ist das was ich eigentlich meinte, nämlich direkt im html code das onclick Attribut zu benutzen, also z.B. <div class="xyz" onclick="foobar()">, ja noch schlimmer
    Kellendil ist offline

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •