yusuf: onclick = function(){}

Hallo Leute!
Würde mich sehr freuen, wenn mir jemand an diesem Beispiel zeigen könnte, wie sich der Programmcode reduzieren lässt.

u[0].onclick = function(){v[0].innerHTML = "0";}  
u[1].onclick = function(){v[1].innerHTML = "1";}  
u[2].onclick = function(){v[2].innerHTML = "2";}  
u[3].onclick = function(){v[3].innerHTML = "3";}  
u[4].onclick = function(){v[4].innerHTML = "4";}  
u[5].onclick = function(){v[5].innerHTML = "5";}  
u[6].onclick = function(){v[6].innerHTML = "6";}  
u[7].onclick = function(){v[7].innerHTML = "7";}

Die einfache for-Schleife allein funktioniert in diesem Fall bekanntlich nicht.

  1. Hi,

    Die einfache for-Schleife allein funktioniert in diesem Fall bekanntlich nicht.

    Aber ein Closure.

    MfG ChrisB

    --
    RGB is totally confusing - I mean, at least #C0FFEE should be brown, right?
  2. Hallo,

    u[0].onclick = function(){v[0].innerHTML = "0";}
    Würde mich sehr freuen, wenn mir jemand an diesem Beispiel zeigen könnte, wie sich der Programmcode reduzieren lässt.

    Das Grundproblem ist hier, dass Kontextdaten verfügbar sein sollen.

    Das kann man über das DOM lösen, indem man die Daten an die jeweiligen DOM-Elemente hängt. Als Data-Attribute oder als JavaScript-Objekteigenschaften. So kann im Event-Handler einfach darauf zugegriffen werden. Das ist aber ein Anti-Pattern – man sollte keine komplexen Daten im DOM speichern.

    Besser ist die objektorientierte Programmierung, bei der es View- bzw. Widget-Objekte gibt, die für Elemente zuständig sind, Event-Handler registrieren und Zugriff auf die Daten haben. Entweder direkt über über ein Model-Objekt. Siehe z.B. Bibliotheken wie Backbone.

    Ein View-Objekt würde Zugriff auf jeweils u[i] und v[i] besitzen und der click-Handler könnte problemlos zum zugehörigen Element kommen.

    Events lassen sich zudem sehr effizient mithilfe von Event-Delegation überwachen. Das dutzendfache Registrieren von Event-Handlern wird dadurch unnötig. Es kann tausende Elemente geben, meistens ist nur *ein* Event-Handler bei einem übergeordneten Element nötig, um die Klicks auf sie zu überwachen.

    Die einfache for-Schleife allein funktioniert in diesem Fall bekanntlich nicht.

    Das ginge über eine Closure.

    var registerHandler = function(el, i) {  
      el.onclick = function() {  
        v[i].innerHTML = i;  
      };  
    };  
      
    for (var i = 0, l = u.length; i < l; i++) {  
      registerHandler(u[i], i);  
    }
    

    Aber dies löst das Problem des Zugriffs auf Kontextdaten in einer sehr umständlichen Weise.

    Warum sind die zugehörigen Elemente denn in zwei Arrays verteilt…? Objektorientiert gesehen sollten sie jeweils gruppiert werden.

    Mathias

  3. Meine Herren!

    u[0].onclick = function(){v[0].innerHTML = "0";}

    u[1].onclick = function(){v[1].innerHTML = "1";}
    u[2].onclick = function(){v[2].innerHTML = "2";}
    u[3].onclick = function(){v[3].innerHTML = "3";}
    u[4].onclick = function(){v[4].innerHTML = "4";}
    u[5].onclick = function(){v[5].innerHTML = "5";}
    u[6].onclick = function(){v[6].innerHTML = "6";}
    u[7].onclick = function(){v[7].innerHTML = "7";}

    
    >   
    > Die einfache for-Schleife allein funktioniert in diesem Fall bekanntlich nicht.  
      
    Ah, ich weiß auf welches Problem die anspielst.  
      
    ~~~javascript
    for (var i = 1; i<=7; i++ ) {  
       u[i].onclick = function(){ v[i].innerHTML = i; };  
    }
    

    Dieser Code würde bei jedem Klick auf eins der Elemente aus u eine 7 in das siebte Element in v schreiben. Das hat damit zu tun, dass die Event-Handler alle die Variable i gemeinsam nutzen. Eine bekannte Lösung dafür sieht so aus:

    for (var i = 1; i<=7; i++ ) {  
       u[i].onclick = function( x ){  
          return function(){ v[x].innerHTML = x; };  
       }( i );  
    }
    

    Das seltsame Konstrukt nennt sich ein Closure.

    Eine andere Schreibweise, die aber das selbe Prinzip aussnutzt:

    for (var i = 1; i<=7; i++ ) {  
       u[i].onclick = function( x ){ v[x].innerHTML = x; }.bind(null, i);  
    }
    

    Ich habe so eine Ahnung, dass dein zu Grunde liegender Fall mit Event-Delegation noch eleganter gelöst werden könnte, zeig doch mal das passende HTML und etwas mehr von dem Skript.

    --
    “All right, then, I'll go to hell.” – Huck Finn
  4. Vielen Dank für Ihre schnellen und hilfreichen Antworten!

    Warum sind die zugehörigen Elemente denn in zwei Arrays verteilt…? Objektorientiert gesehen sollten sie jeweils gruppiert werden.

    Ich werde mir darüber Gedanken machen.
    Im Allgemeinen müssen Elemente nichts Gemeinsames haben und sind nur über den Index miteinander verbunden.

    1. Meine Herren!

      Warum sind die zugehörigen Elemente denn in zwei Arrays verteilt…? Objektorientiert gesehen sollten sie jeweils gruppiert werden.

      Im Allgemeinen müssen Elemente nichts Gemeinsames haben und sind nur über den Index miteinander verbunden.

      Der Index ist keine Eigenschaft eines Elements. Den Index gibt es überhaupt nur, weil die Datenstruktur, mit der du die Elemente verwaltest (NodeList oder Array wie ich vermute), zufällig (1) einen Zugriffsmechanismus anhand eines Index' bietet.

      (1) Zufällig stimmt natürlich nicht ganz. Aber du machst du Korrespondenz der Elemente anhand eines Implementations-Details fest, anstatt eine Schnittstelle dafür zur Verfügung zu stellen.

      Nochmal in anderen Worten gefasst, weil die Essenz dieser Aussage schwierig zu vermitteln ist: Du hast Elemente a und b, die miteinander in Verbindung stehen. Das Element a ist uns bekannt, wir wollen uns nun das zugehörige Element b holen. In deiner bisherigen Lösung, müssen wir dafür Kenntnisse über die Datenstrukturen haben, die a und b verwalten. Wir müssen uns erst den Index von Element a besorgen und dann in der zweiten Liste das Element mit dem gleichen Index raussuchen. Ein schönerer Entwurf wäre es, wenn es eine Schnittstelle gäbe, in die wir a reinpacken und die uns sofort b liefert, und zwar ohne das wir Umwege gehen müssen. Ich hoffe, ich konnte mich einigermaßen Verständlich ausdrücken.

      --
      “All right, then, I'll go to hell.” – Huck Finn
      1. Ein schönerer Entwurf wäre es, wenn es eine Schnittstelle gäbe, in die wir a reinpacken und die uns sofort b liefert, und zwar ohne das wir Umwege gehen müssen.

        Du meinst Maps?
        http://www.peterkroener.de/es6-maps-sets-weak-maps/
        http://www.nczonline.net/blog/2012/10/09/ecmascript-6-collections-part-2-maps/

        Wird es in der kommenden ECMAScript-Version 6 geben, für ECMAScript-5-Browser ist ein Shim möglich.
        https://github.com/paulmillr/es6-shim

        Mathias

        1. Meine Herren!

          Ein schönerer Entwurf wäre es, wenn es eine Schnittstelle gäbe, in die wir a reinpacken und die uns sofort b liefert, und zwar ohne das wir Umwege gehen müssen.

          Du meinst Maps?

          Ich muss zugeben, ich habe die ganze an Maps gedacht, aber wollte mich allgemeiner fassen, denn denkbar wäre auch eine gewöhnliche Assoziation:

          a = {};  
          b = {};  
            
          a.foo = b;
          

          Oder eine Funktion, die die Korrespondenz dynamisch aushandelt:

          function getBFromA( a ) {  
             var b;  
             // Voodoo  
             return b;  
          }
          

          Die Qual der Wahl muss erst in einem konkreten Anwendungsfall durchlitten werden.

          --
          “All right, then, I'll go to hell.” – Huck Finn