dedlfix: Neues Anfänger-Tutorial für JavaScript: Tic-Tac-Toe

Beitrag lesen

problematische Seite

Tach!

Da dachte ich mir damals, den Post könnte ich zu einem richtigen Artikel ausbauen. Da ich gerade Weihnachtsferien habe und dem allgemeinen Aufruf nach Anfänger-Tutorials insbesondere für JavaScript einen Beitrag spendieren wollte, isser nun im Wiki und möchte kritisiert und verbessert werden:

JavaScript/Tutorials/TicTacToe

Ich würde es gern sehen, wenn die Instantiierungen anonymer Funktionen durch die Variante 2, also die IIFE-Schreibweise ausgetauscht würden. Diese Schreibweise trifft man doch heutzutage häufiger in der freien Wildbahn an (soll heißen, die new-Schreibweise hab ich für diesen Zweck so noch nicht bewusst wahrgenommen). Ich hab da mal eben einen Erläuterungsartikel dazu geschrieben, siehe obigen Link.

Das MDN sagt, dass querySelectorAll() eine non-live NodeList liefert und keine lebendige. Dieses Detail ist aber für den Artikel nicht weiter relevant, weil die Anzahl der Spiele auf der Seite sich nicht im laufenden Betrieb ändern wird. Es ist sicher auch wenig sinnvoll, mehr als ein Spiel auf die Seite zu bringen, solange man eh nur zwei Personen abwechselnd agieren lässt. Anders wäre es, wenn ein Spielleiter alle Spiele in einem Netzwerk überwachen möchte und da welche hinzukommen oder wegfallen. Aber das ist kein Thema für einen Einsteigerartikel. Jedenfalls könnte man dem Spiel auch eine ID statt einer Klasse vergeben. Es sei denn, du möchtest nur einen Grund haben, warum das eigentliche Spiel in einer Funktion (TicTacToe) ausgelagert ist. Aber das könnte man auch mit guter Strukturierung und Bilden von Zuständigkeitseinheiten begründen.

Statt for mit der Zählvariable i fände ich ja forEach() ausdrucksstärker, vor allem, weil man dann nicht games[i] sondern game zur Repräsentation eines einzelnen Spiels hat. Dummerweise liefert querySelectorAll() kein Array sondern eine NodeList, und die hat keine Array-Methoden. Was aber geht, wäre for...of, was aber auf Microsoft-Seite erst im Edge-Browser verfügbar ist. Jedenfalls kommt man damit an die Ausdrucksstärke von forEach heran.

Es gibt einen entscheidenden Unterschied zwischen

var foo = function() {...};

und

function foo() {...};

Wenn man eine Funktion als Variable anlegt, muss die Ausführung des Codes an der Stelle vorbeigekommen sein, damit diese Funktionsvariable existiert. Als "ordentliche" Funktion kann sie auch irgendwo im Code hinter ihren Aufrufen stehen, weil sie dann quasi zur Compile-Zeit gefunden und erstellt wird und somit generell zur Laufzeit zur Verfügung steht (natürlich auch nur innerhalb des Scopes).

Variablen-/Parameternamen bitte ausschreiben. Bei i als allgemein übliche Laufvariable ist das noch kein Problem (besser: forEach/for...of verwenden, wenn möglich), aber el und e sind gerade für Anfänger, die nicht wissen, was die Funktionen für Parameter erwarten, erklärungsbedürftig. Also lieber element und event nehmen. Das gilt im Prinzip auch für Code, der nicht nur Anfängern gewidmet ist. Für absichtlich unleserlichen Code gibt es Uglifier ;)

Im Gegensatz zu querySelectorAll() erzeugt getElementsByTagName() (egal ob von document oder element) diesmal wirklich eine live list, allerdings keine NodeList, sondern eine HTMLCollection (die aber leider auch nicht von Array erbt).

In check() ist es besser, statt !finished nur auf finished zu prüfen und in dem Fall die Funktion zu verlassen. Das reduziert eine Einrückungsebene, besonders weil es keinen Else-Zweig gibt oder genereller Code nach diesem if kommt.

"Es hat einen Sinn, die Variablendeklaration an den Anfang der Funktion zu setzen und nicht erst im Anweisungsblock des if-Statements. Das ist gute Programmierertradition, da damit der Code für andere übersichtlicher wird." - Njein, kann man so sehen, kann man aber auch anders sehen. Besser sind kleinere lokale übersichtliche Scopes, statt dass man im Großen versucht den globalen Scope zu meiden, im kleinen aber Variablen im gesamten Scope rumliegen hat. Im Falle von i ist es sogar unübersichtlicher, weil i nur ganz lokal benötigt wird und nicht in der gesamten Funktion. Dafür hat man sich auch in der kommenden JavaScript-Version das Schlüsselwort let ausgedacht, das den Scope von Variablen nochmal deutlich einschränken kann. Ansonsten muss man sagen: Kommt drauf an. Manchmal benötigt man eine Variable wirklich im gesamten Scope und manchmal eben nicht.

Zur Ermittlung ob full oder nicht, kann man nach dem ersten false die Schleife abbrechen, "fuller" wird es nämlich mit den anderen Werten auch nicht. Noch besser wäre es, every() zu nehmen, was im vorliegenden Ansatz wieder daran krankt, dass eine HTMLCollection kein Array ist.

"Wenn wir prüfen wollen, ob der String leer ist, genügt es nicht mit dem ==-Operator zu prüfen, da JavaScript intern Wertetypen umrechnen kann, um verschiedene Typen miteinander zu vergleichen." - Oh doch, das genügt in dem Fall vollkommen, weil beim Vergleich von zwei Strings (hier className mit einem Stringliteral) kein anderer Wertetyp beteiligt ist. Anders sähe der Fall aus, wenn ein Integer oder Boolean beteiligt wäre - ist aber nicht. Es hat schon seinen Sinn, warum man === bevorzugt, aber die Begründung passt an der Stelle nicht. Das hier ist eher nur ein Fall von "mach ich immer so, mach ich hier auch so". className ist definiert als string, und selbst wenn man da 0 (Integer-Literal) reinschreibt, kommt "0" (String) beim Lesen raus.

"In diesem if-Statement werden zwei Werte mit einem logischen Oder verknüpft. Hier macht man sich die automatische Typumwandlung von JavaScript zunutze." - Ist das nicht etwas inkonsequent? Einerseits die automatische Typkonvertierung mithilfe von === vermeiden (abgesehen von obigem Sinn-Argument für den dortigen Fall) und andererseits darauf zu bauen? Abgesehen von dieser Stichelei, pfeif ich persönlich auf solche Konsistenzen aus niederen Beweggründen. Ich brauche die Erfahrungswerte, die ich bekomme, wenn ich in solche potentiellen Fehlerquellen reintappe. Es bringt mir nichts, solche Stellen mit der Konsequenz selbst aufgestellter Regeln zu vermeiden, um den Kopf frei für andere Dinge zu haben, wenn ich sie dann im Falle eines Falles nicht mehr erkenne. Die Problematik verschwindet ja nicht aus der Welt, egal wie sehr man sich im Einzelnen darum bemühen mag.

Für script und style, obwohl ihr Inhalt als CDATA definiert ist, gab es in HTML4 die Sonderregel, dass darin (sprich bis zum ersten </) kein Markup interpretiert wurde ("Although ..."). Die Verwendung eines //<![CDATA[...//]]>-Blocks ist laut Standard nicht notwendig. Vielleicht gab/gibt es einige Situationen, für die die Browser das brauchen, aber da ist mir auch noch keine über den Weg gelaufen. In HTML5 ist das Regelwerk von script gehörig aufgebohrt worden (und ich hab keine Lust das alles zu lesen), aber dass nun darin Markup interpretiert wird, kann ich mir nicht vorstellen. Der CDATA-Rahmen kann also weg. Und type="text/javascript" ist der Standard-Wert und kann damit auch weggelassen werden.

Bis hier waren das Anmerkungen von mir (doch so viele?), die, wenn sie überzeugend waren, gern eingearbeitet werden können. Wenn nicht, bin ich auch nicht traurig. Abseits davon hier noch eine weitere Bemerkung der Vollständigkeit halber. Wenn man es "richtig" macht, stochert man lieber nicht in der Ausgabe herum, um Werte für die Geschäftslogik zu bekommen. Wenn man an der Ausgabe Änderungen vornehmen möchte (zum Beispiel statt Tabelle was anderes), muss man durch die Geschäftslogik durchlaufen und dort alle Element- und/oder Klassennamen ändern. Besser ist, man hat eine separate Datenhaltung. Der kann man dann auch einen sprechenden Namen geben und muss sich den Sinn der Programmelemente nicht aus dem Kontext erarbeiten. In dem Fall wäre für das Spielfeld ein Array of Arrays mit jeweils drei Elementen angebracht. Diese Datenhaltung nimmt man nun zum Berechnen des Spielstandes und auch als Datengrundlage für die Darstellung. Dann muss man nicht fragen, ob und welcher className gesetzt ist, man setzt ihn einfach entsprechend dieses Spielfeld-Array-Inhalts. Damit macht man dann auch einen deutlichen Schritt hin zum EVA-Prinzip. Wenn man das Spiel mit AngularJS erstellen wollte, sähe man den Vorteil einer solchen Trennung noch deutlicher, denn da ist schon vom Konzept her die Ausgabe von der Geschäftlogik abgekoppelt. Die Spiel-Logik sitzt im Controller, oder ausgelagert in einem Service, und die View (sprich die Angular-Direktiven im HTML) bekommen das Spielfeld (oder die Werte daraus, die für sie von Interesse sind) hingereicht und kümmert sich selbst um die Darstellung. Für die Klick-Events gibt es auch ein paar entsprechende Wege. Statt Spielfeld-Datenhaltung wäre es deutlich umständlicher, die Werte aus dem DOM auszulesen, wenn man das auf Angular-Weise tun wollen würde.

dedlfix.

3 205

Neues Anfänger-Tutorial für JavaScript: Tic-Tac-Toe

Felix Riesterer
  • meinung
  • seitenbewertung
  • selfhtml-wiki
  1. 0
    Matthias Scharwies
    1. 0
      Felix Riesterer
      1. 0
        Matthias Apsel
        1. 0
          Felix Riesterer
          1. 0
            Der Martin
            1. 0
              Gunnar Bittersmann
              1. 0
                Der Martin
                1. 0
                  Gunnar Bittersmann
                  1. 0
                    Matthias Apsel
                    1. 0
                      Gunnar Bittersmann
                      1. 0
                        Der Martin
                        1. 0
                          Gunnar Bittersmann
                2. 0
                  Felix Riesterer
                  1. 0
                    Camping_RIDER
                    1. 0
                      Gunnar Bittersmann
                      1. 0
                        Camping_RIDER
          2. 0
            Gunnar Bittersmann
            1. 3
              Felix Riesterer
              1. 1
                Gunnar Bittersmann
                1. 0
                  Felix Riesterer
                  1. 0
                    Gunnar Bittersmann
                    1. 1
                      Matthias Apsel
                      1. 0
                        Gunnar Bittersmann
                        1. 0
                          Matthias Apsel
                          1. 0
                            Gunnar Bittersmann
                            1. 0
                              Camping_RIDER
                              1. 0
                                Gunnar Bittersmann
                                1. 0
                                  JürgenB
                                  1. 0
                                    Gunnar Bittersmann
                                    1. 0
                                      JürgenB
                                      1. 0
                                        Gunnar Bittersmann
                                2. 4
                                  Camping_RIDER
                                  1. 0
                                    Gunnar Bittersmann
                                    1. 0
                                      Camping_RIDER
                                      1. 0
                                        Gunnar Bittersmann
                                        1. 0
                                          Felix Riesterer
                                          1. 0
                                            Gunnar Bittersmann
                                            1. 0
                                              Camping_RIDER
                                              1. 0
                                                Gunnar Bittersmann
                                                1. 1

                                                  Kommunikation

                                                  Camping_RIDER
                                                  • meinung
                                                  • menschelei
              2. 0
                Richard Rüfenacht
                1. 0
                  Gunnar Bittersmann
                  1. 0
                    Richard Rüfenacht
                  2. 0
                    Auge
                    • meinung
                    • selfhtml-wiki
                    1. 0
                      Gunnar Bittersmann
                2. 0
                  Auge
                  • meinung
                  • selfhtml-wiki
    2. 0
      Gunnar Bittersmann
      1. 0
        Felix Riesterer
        1. 0

          Großes ẞ

          Gunnar Bittersmann
          • typografie
          1. 0
            Camping_RIDER
            1. 0
              Gunnar Bittersmann
              1. 0
                Camping_RIDER
                1. 0
                  Gunnar Bittersmann
                  1. 0
                    Camping_RIDER
                    1. 0
                      Der Martin
                      1. 0
                        Christian Kruse
                        1. 0
                          Der Martin
                        2. 0
                          Gunnar Bittersmann
                          1. 0
                            Christian Kruse
                            1. 0
                              Camping_RIDER
                            2. 0
                              Christian Kruse
                          2. 0
                            Der Martin
                            1. 0
                              Gunnar Bittersmann
                              • menschelei
                    2. 0
                      Matthias Apsel
            2. 0
              MudGuard
              1. 0
                Christian Kruse
              2. 0
                Gunnar Bittersmann
                1. 0
                  Felix Riesterer
              3. 0
                Gunnar Bittersmann
                1. 0
                  Matthias Apsel
          2. 2

            Großes ẞ - der Vollständigkeit halber

            Bai Se Wey
            1. 0
              Gunnar Bittersmann
              1. 1

                Großes ẞ - der Kleinlichkeit halber

                Bai Se Wey
      2. 0
        Klawischnigg
        1. 0
          Camping_RIDER
          • menschelei
  2. 0
    Gunnar Bittersmann
    1. 0
      JürgenB
      1. 0
        Matthias Apsel
        1. 0
          Christian Kruse
          1. 0
            JürgenB
            1. 0
              Tabellenkalk
          2. 0
            Camping_RIDER
      2. 0
        Gunnar Bittersmann
        1. 0
          Felix Riesterer
          1. 0
            Gunnar Bittersmann
            • selfhtml-wiki
            • svg
            1. 0
              Felix Riesterer
              1. 0
                Camping_RIDER
                1. 0
                  Gunnar Bittersmann
                  • selfhtml-wiki
                  • typografie
                  1. 0
                    Auge
                    1. 0
                      Gunnar Bittersmann
                      1. 0
                        Christian Kruse
                        1. 0
                          Gunnar Bittersmann
                          1. 3
                            Christian Kruse
              2. 0
                Gunnar Bittersmann
                1. 1
                  Camping_RIDER
                  1. 0
                    Gunnar Bittersmann
    2. 0
      Felix Riesterer
  3. 0
    JürgenB
    1. 0
      Felix Riesterer
      1. 0
        Gunnar Bittersmann
        1. 0
          Matthias Apsel
        2. 0
          Felix Riesterer
        3. 0
          Camping_RIDER
          1. 0
            Gunnar Bittersmann
            1. 0
              JürgenB
              1. 0
                Auge
              2. 0
                Camping_RIDER
              3. 0
                Gunnar Bittersmann
                1. 0
                  Gunnar Bittersmann
      2. 0
        JürgenB
  4. 4
    dedlfix
    1. 0
      Matthias Scharwies
      1. 0
        dedlfix
        1. 0
          Matthias Scharwies
          1. 0
            dedlfix
            1. 0
              Matthias Scharwies
              1. 0
                dedlfix
          2. 0
            Matthias Apsel
            1. 0
              Matthias Scharwies
            2. 0
              Camping_RIDER
    2. 0
      Felix Riesterer
      1. 0
        Gunnar Bittersmann
      2. 0
        dedlfix
  5. 0
    pl
    1. 0
      Felix Riesterer
      1. 0
        pl
        1. 0
          Gunnar Bittersmann
  6. 0
    Msass
  7. 5
    Gunnar Bittersmann
    1. 1
      dedlfix
      1. 0
        Gunnar Bittersmann
        1. 2
          Felix Riesterer
          1. 1
            Gunnar Bittersmann
            1. 1
              Felix Riesterer
              1. 0
                Gunnar Bittersmann
                1. 0
                  Gunnar Bittersmann
                  1. 0
                    Felix Riesterer
                    • meinung
                    • selfhtml-wiki
                2. 0
                  Felix Riesterer
                  • meinung
                  • selfhtml-wiki
            2. 3
              Matthias Apsel
    2. 0
      Matthias Apsel
      1. 0
        Matthias Apsel
        1. 2
          dedlfix
      2. 0
        Gunnar Bittersmann
        1. 0
          Felix Riesterer
          1. 0
            Gunnar Bittersmann
            1. 0
              Camping_RIDER
              1. 0
                Gunnar Bittersmann
                1. 1
                  Felix Riesterer
                  1. 0
                    Gunnar Bittersmann
                    1. 0
                      Felix Riesterer
            2. 0
              Felix Riesterer
              1. 0
                Gunnar Bittersmann
    3. 0
      Felix Riesterer
      1. 1
        Gunnar Bittersmann
        1. 0
          Gunnar Bittersmann
    4. 0

      Wer hat gewonnen?

      Matthias Apsel
      • javascript
      1. 0
        Gunnar Bittersmann
    5. 0
      Matthias Apsel
    6. 0
      Matthias Apsel
      1. 0
        Matthias Apsel
    7. 6
      Felix Riesterer
      1. 1
        Der Martin
        1. 1
          Felix Riesterer
          1. 0
            Matthias Scharwies
            1. 0
              Felix Riesterer
              1. 0
                Gunnar Bittersmann
          2. 1
            Gunnar Bittersmann
            1. 0
              Felix Riesterer
              1. 0
                Gunnar Bittersmann
                1. 0
                  Felix Riesterer
                  1. 0
                    Gunnar Bittersmann
                    1. 0
                      Matthias Apsel
                2. 1

                  Roter-Faden-Artikel in Wikis

                  Camping_RIDER
              2. 0
                Gunnar Bittersmann
      2. 1
        Gunnar Bittersmann
  8. 0
    Gunnar Bittersmann
    1. 0
      Felix Riesterer
      • meinung
      • selfhtml
      • selfhtml-wiki
    2. 0
      Camping_RIDER
  9. 1
    Gunnar Bittersmann
    1. 0
      Felix Riesterer
      1. 0
        Gunnar Bittersmann
        1. 0
          Felix Riesterer
          1. 0
            Gunnar Bittersmann
            1. 2
              Mitleser
              1. 0
                Gunnar Bittersmann
              2. 0
                Matthias Apsel
                1. 0
                  Gunnar Bittersmann
                  1. 1
                    Camping_RIDER
                    1. 1
                      Gunnar Bittersmann
                      1. 1
                        Felix Riesterer
                        • meinung
                        • selfhtml-wiki
                        1. 0
                          Gunnar Bittersmann
                          1. 1
                            Camping_RIDER
                            1. 0
                              Gunnar Bittersmann
                              1. 1
                                Matthias Apsel
                        2. 0
                          Gunnar Bittersmann
                          1. 2
                            Tabellenkalk
                    2. 1
                      Gunnar Bittersmann
                      1. 0
                        Camping_RIDER
                        1. 1
                          Der Martin
                      2. 0
                        Matthias Apsel
          2. 1
            Gunnar Bittersmann
    2. 0
      Camping_RIDER
      1. 0
        Gunnar Bittersmann
        1. 1
          Camping_RIDER