Matthias Apsel: JavaScript-Beispiele im Wiki

Hallo alle,

function Ausgeben() {
  var pi = Math.PI,
      elem = document.getElementById('Ausgabe');
  elem.innerHTML = 'π ≈ ' + pi;
}

vs.

function Ausgeben() {
  document.getElementById('Ausgabe').innerHTML = 'π ≈ ' + Math.PI;
}

Welche Variante wäre in unserem Wiki warum zu bevorzugen?

Bis demnächst
Matthias

--
Dieses Forum nutzt Markdown. Im Wiki erhalten Sie Hilfe bei der Formatierung Ihrer Beiträge.

akzeptierte Antworten

  1. Servus!

    Ich fänd' die obere Variante besser/übersichtlicher, da dort die Variablen am Anfang klar deklariert werden.

    Natürlich wird man wsl. später in der Praxis die Ausgabe nur einmal ansprechen und deshalb keine Variable verwenden.

    
    function ausgeben() {
      var pi = Math.PI,
          elem = document.getElementById('ausgabe');
      elem.textContent = 'π ≈ ' + pi;
    }
    

    Ich würde Funktionen, Variblen in CamelCase schreiben und klein beginnen, Ids und Klassen konsequent kleinschreiben. Dies ist in alten Besipielen andersrum gemacht worden.

    Ich würde statt innerHTML textContent verwenden.

    Herzliche Grüße

    Matthias Scharwies

    --
    Es gibt viel zu tun: ToDo-Liste
    1. Hallo,

      var pi = Math.PI,

      warum das Umkopieren?

      1. wird hier ja oft grundsätzlich gegen das Umkopieren gewettert und
      2. wird dadurch plötzlich aus einer Konstanten eine Variable⁉️

      Gruß
      Kalk

      1. Hallo Tabellenkalk,

        var pi = Math.PI,

        warum das Umkopieren?

        1. wird hier ja oft grundsätzlich gegen das Umkopieren gewettert und
        2. wird dadurch plötzlich aus einer Konstanten eine Variable⁉️

        Damit würde sich

        function ausgeben() {
          var elem = document.getElementById('ausgabe');
          elem.textContent = 'π ≈ ' + Math.PI;
        }
        

        ergeben und du könntest die Frage stellen

        var elem = document.getElementById('ausgabe');

        „Warum das Umkopieren?“

        und wir wären bei

        function ausgeben() {
          document.getElementById('ausgabe').textContent = 'π ≈ ' + Math.PI;
        }
        

        Bis demnächst
        Matthias

        --
        Dieses Forum nutzt Markdown. Im Wiki erhalten Sie Hilfe bei der Formatierung Ihrer Beiträge.
        1. Hallo,

          und wir wären bei …

          … dem anderen Thread, in dem es um die Länge von Funktionen geht.
          Ein Einzeiler! YYeahh‼️

          Gruß
          Kalk

        2. Hallo Matthias Apsel,

          var elem = document.getElementById('ausgabe');

          „Warum das Umkopieren?“

          Dafür spräche:

          • Man sammelt am Anfang alle Elemente ein, die man so benötigt
          • bei mehrfacher Verwendung braucht das Element nicht erneut gesucht zu werden
            • vielleicht sind die Browser aber auch klug genug, sich intern eine Referenz zu merken. (molily schrieb mal sinngemäß „Was macht dich so sicher, dass die Browser jedesmal auf Neue das DOM durchhecheln?“
            • das ist hier auch so ungefähr Konsens beim Umkopieren von $_POST

          Bis demnächst
          Matthias

          --
          Dieses Forum nutzt Markdown. Im Wiki erhalten Sie Hilfe bei der Formatierung Ihrer Beiträge.
          1. Hallo Matthias,

            • das ist hier auch so ungefähr Konsens beim Umkopieren von $_POST

            $_POST muss genauso wenig oder viel wie eine Variable „gesucht werden“. Außerdem verliert man dann den Überblick, woher die Variablen kommen (falls das mal relevant sein sollte).

            Siehe auch: https://forum.selfhtml.org/self/2017/feb/13/stmt-bind-param/1687078#m1687078

            Gruß
            Julius

            1. Hallo Julius,

              • das ist hier auch so ungefähr Konsens beim Umkopieren von $_POST

              $_POST muss genauso wenig oder viel wie eine Variable „gesucht werden“. Außerdem verliert man dann den Überblick, woher die Variablen kommen (falls das mal relevant sein sollte).

              Ja, ich habe mich ungenau ausgedrückt:

              Falls man dem Argument, „Ich möchte Schreibarbeit sparen“ aufgeschlossen gegenübersteht, kann man
              hä = $_POST['ein_ganz_langer_sprechender_bezeichner']
              machen. Das lohnt sich aber erst, wenn man auch mehrfach benötigt und birgt natürlich auch Gefahren und sollte deshalb mMn. unterbleiben.

              Bis demnächst
              Matthias

              --
              Dieses Forum nutzt Markdown. Im Wiki erhalten Sie Hilfe bei der Formatierung Ihrer Beiträge.
              1. Lieber Matthias,

                es hat vor allem dann einen Sinn, wenn Du das kopierte(!) Array anschließend verändern willst, aber später das originale Array unverfälscht wieder benötigst.

                Liebe Grüße,

                Felix Riesterer.

              2. hä = $_POST['ein_ganz_langer_sprechender_bezeichner']

                Parse error: syntax error, unexpected '=' in hä.php
                SCNR 😉

                wenn man hä auch mehrfach benötigt

                Es gibt drei Argumente, die das Zwischenspeichern in einer Variablen begründen. Dieses ist eins davon.

                Das zweite ist die Notwendigkeit, $hä erstmal auf Gültigkeit zu testen bevor man damit weitermacht. Im Falle des getElementById wäre das eine Abfrage, ob das Element überhaupt gefunden wurde. OB man eine solche Abfrage braucht, hängt von der Dynamik der Seite ab, in der man das Element sucht.

                Das dritte Argument ist Debug-Freundlichkeit. Wenn ich elend lange Ausdrücke aufbaue, dann ist es mühsam, sich Zwischenwerte innerhalb dieses Ausdrucks beim Debuggen anzuschauen. Man muss den Ausdruck, der den Zwischenwert erzeugt, in das Watch-Fenster des Debuggers übertragen, und das funktioniert nur, wenn dieser Ausdruck idempotent ist.

                Das Argument der Lesbarkeit greift nicht wirklich, die kann man auch durch entsprechende Zeilenumbrüche und Einrückungen erreichen.

                Rolf

      2. Servus!

        var pi = Math.PI,

        warum das Umkopieren?

        1. wird hier ja oft grundsätzlich gegen das Umkopieren gewettert und

        Ich fänd's übersichtlicher, bin aber wirklich nicht maßgebend.

        1. wird dadurch plötzlich aus einer Konstanten eine Variable⁉️

        Also: const pi = Math.PI,

        Dafür ist const ja geschaffen worden, oder?

        Herzliche Grüße

        Matthias Scharwies

        --
        Es gibt viel zu tun: ToDo-Liste
        1. Lieber Matthias,

          var pi = Math.PI,

          warum das Umkopieren?

          ich halte es für falsch. Später sehe ich pi nicht mehr an, dass es Math.PI enthält. Es könnte auch ein Näherungswert wie 22/7 sein.

          Also: const pi = Math.PI,

          Nein. Anstatt pi notiert man (vor allem der Übersichtlichkeit wegen!) das originale Math.PI. Die Übersichtlichkeit steigt, da die Herkunft des Wertes eindeutig ist.

          Dafür ist const ja geschaffen worden, oder?

          Es ist für unveränderliche Werte geschaffen worden, ja. Math.PI ist ein solcher. Man kann eine Variable anlegen, deren Inhalt (lies: die dahinter stehende Objektinstanz des zugewiesenen Wertes!) man später nicht mehr austauschen kann (bei zugewiesenen Objekten kannst Du Eigenschaften und Methoden sehr wohl später verändern). Aber für die mathematische Konstante Pi ist das nicht sinnvoll, da es dafür bereits eine eindeutige und mit nur wenig Schreibaufwand verbundene Notation gibt.

          Liebe Grüße,

          Felix Riesterer.

  2. Tach!

    function Ausgeben() {
      var pi = Math.PI,
          elem = document.getElementById('Ausgabe');
      elem.innerHTML = 'π ≈ ' + pi;
    }
    

    vs.

    function Ausgeben() {
      document.getElementById('Ausgabe').innerHTML = 'π ≈ ' + Math.PI;
    }
    

    Welche Variante wäre in unserem Wiki warum zu bevorzugen?

    In einem Nicht-nur-Beispiel-Programm kommen noch ganz andere Bedingungen vor, worauf man entsprechend anderes reagieren wird.

    Zunächst mal, Umkopieren ohne stichhaltige Begründung, das den Code länger macht, sollte man vermeiden. Math.PI ist eindeutig genug und bereits eine Konstante. Kopieren in eine Variable oder andere Konstante ergibt keine Vorteile. Anders sieht es aus, wenn man PI in einem Teilausdruck braucht, den man mehrfach verwendet. Dann lohnt es sich schon eher, das Zwischenergebnis abzulegen. Das aber weniger aus Performance-Gründen, sondern um die Codemenge und damit die Fehlermöglichkeiten gering zu halten.

    Eine Variable (oder besser const) für das HTML-Element anzulegen, ist in dem Beispiel auch nicht nötig. Bei mehrfachem Zugreifen hingegen lohnt es sich wiederum. Aber vielleicht sollte man die Funktion lieber so umschreiben, dass man das Ergebnis der Berechnung zurückgibt und nicht zwei Dinge gleichzeitig und das recht starr macht: Berechnen (naja, hier nicht wirklich) und Ausgabe in ein spezifisches Element. Im Grunde genommen braucht dieses Beispiel gar keine Funktion und ein Einzeler ist mehr als gerechtfertigt.

    Machen wir die Sache mal ein wenig komplexer und wollen zu einem Radius den Umfang ausgeben lassen.

    function circumference(radius) {
      return 2 * Math.PI * radius;
    }
    
    function output(element, value) {
      element.textContent = value;
    }
    

    Und da wo die Berechung angestoßen wurde:

    output(document.getElementById('result'), circumference(radius));
    

    Die Funktion circumference ist bezüglich ihrer Gestaltung soweit in Ordnung. Ich habe sie direkt aufgerufen, weil ihr Ergebnis hier nur einmal benötigt wird. Eine Variable (const) lohnt sich ers ab mehrfacher Verwendung. Oder wenn der Audruck deutlich komplexer wird als circumference(radius) und man zwecks Debugging-Möglichkeit die Zwischenergebnisse in einer Variable haben möchte.

    Kaum gerechtfertigt hingegen ist output() in ihrem jetzigen Zustand. Andererseits sieht man da aber das Prinzip "don't look for things". Die Funktion geht nicht auf die Suche, sondern bekommt das Element übergeben, mit dem sie arbeiten soll. Man muss nicht in ihr Inneres schauen, um zu sehen, wo die Ausgabe landen wird. Gestaltet man sie stattdessen so:

    function output(id, value) {
      document.getElementById(id).textContent = value;
    }
    

    ist sie eingeschränkt auf die Übergabe einer ID. Es wird auch nicht viel besser, wenn man querySelector() statt getElementById() nimmt. Sie wird dadurch zwar flexibler, aber man kann auch dann noch keine bereits vorhandene Referenz auf ein Objekt übergeben und lässt in der Funktion erneut das DOM absuchen. Apropos DOM, es ist vielleicht auch nicht notwendig, immer das gesamte DOM zu befragen. Nur in Teilen suchen kann diese Funktion aber auch nicht. - Eine Funktion zu schreiben, die all diese Nachteile auszugleichen versucht, erschafft nur eine eierlegende Wollmilchsau. Sieht erstmal toll aus, ist aber ein komplexes Gebilde mit allen Nachteilen eines solchen.

    Für dieses einfache Beispiel sehe ich keine Berechtigung für die Funktion output. Mir fällt aber auch grad kein komplexeres Beispiel ein, für das sich eine Funktion anbietet.

    Übrigens, moderne Anwendungsentwicklung unter Javascript hat solche Probleme nicht (dafür aber andere). Angenommen, eine SPA wäre für den Aufgabenumfang und die Anforderungen gerechtfertigt, und man entscheidet sich für Angular, dann käme das Berechungsergebnis in einer Eigenschaft des Controllers zu liegen, der für die Erledigung der aktuellen Aufgabe aufgerufen wurde. Der Radius kommt über Binding zum Controller. Im Template verweist das value-Attribut eines Input-Feldes auf eine Eigenschaft des Controllers und das Framework sorgt dafür, dass der Wert dort abgelegt wird, wenn der bevor der Code im Controller gestartet wird. Zum Controller ist auch noch ein Template konfiguriert, und in diesem nimmt man Bezug auf die Eigenschaften des Controllers, à la <output>{{circumference}}</output>. Im Controller ist also nur die Berechnung und die Zuweisung deren Ergebnisses notiert. Alle anderen Begleitumstände, zum Beispiel wie das aktuelle HTML aussieht, interessiert den Controller nicht. Komplexere Berechnungen werden auch gern in einen Service ausgelagert, so dass der Controller nicht überladen wird. (Der Controller ist üblicherweise als Klasse (TypeScript for the win!) ausgelegt, der Service vielleicht auch oder es ist nur eine Funktion.)

    Nochmal zurück zur eigentlichen Frage. Der geneigte Leser des Wikis wird sicherlich nicht bemerken, warum welche der beiden Varianten letztlich genommen wurde. Wir werden nicht davon ausgehen können, dass er seinen Code in dem Stil schreibt, wie wir ihn anwenden. Um auch für diese Aspekte sensibilisiert zu werden, müsste man ihn mit einer Abhandlung versorgen, die sich mit den Vor- und Nachteilen diverser Programmierstile beschäftigt.

    Konsistenz der Konsistenz willen ist auch nicht meine bevorzugte Arbeitsweise. Einigt man sich auf die Regel, Einzeiler zu verwenden, wird es bald unleserlich bei komplexen Vorgängen. Lebt man nach der Maxime, alles in Variablen abzulegen, wird der Code in vielen Fällen größer und geschwätziger als notwendig. Ich handle lieber nach: aktuelle Teilaufgabe analysieren, entscheiden was dafür das Beste ist, und bei Bedarf refakturieren.

    dedlfix.

    1. Hallo Matthias,

      ich hänge mich hier mal mit einen anderen „Javascript-Problem“ rein:

      Ich binde bei Beispielen im Wiki extere Scripte per Javascript ein:

      <!-- Damit das Beispiel auch in der Frickl-Ansicht funktioniert, werden die Scripte per Javascript nachgeladen und der Eventlistener von DOMContentLoaded auf load geändert. -->
      <!--<script src="JS-Anw-FktPlot-grafik_canvas.js"></script>-->
      <!--<script src="JS-Anw-FktPlot-plot.js"></script>-->
      <!--<script src="JS-Anw-FktPlot-fkt-plotter.js"></script>-->
      <script>
      "use strict";
      var SW = {};
      SW.loadjs = function (jsfile) {
      	var s = document.createElement("script");
      	s.src = "/extensions/Selfhtml/example.php/Beispiel:"+jsfile;
      	s.type = "text/javascript";
      	document.getElementsByTagName("head")[0].appendChild(s);
      }
      // load "JS-Anw-FktPlot-grafik_canvas.js"
      SW.loadjs("JS-Anw-FktPlot-grafik_canvas.js");
      // load "JS-Anw-FktPlot-plot.js"
      SW.loadjs("JS-Anw-FktPlot-plot.js");
      // load "JS-Anw-FktPlot-fkt-plotter.js"
      SW.loadjs("JS-Anw-FktPlot-fkt-plotter.js");
      </script>
      

      Ich glaube, der Grund war, die Scripte auch im Frickler laufen lassen zu können. In einem anderen Beispiel habe ich gesehen, das das „normale“ Einbinden im body auch funktioniert. Welche Variante haltet ihr bei Wiki-Beispielen für die Bessere. Mir gefällt die jetzige, da zu trickig, nicht so gut.

      Kann man in der Beispielbox auch Links (auf die externen Scripte) setzen?

      Gruß
      Jürgen

      1. Hallo JürgenB,

        Kann man in der Beispielbox auch Links (auf die externen Scripte) setzen?

        Wie meinst du das?

        Bis demnächst
        Matthias

        --
        Dieses Forum nutzt Markdown. Im Wiki erhalten Sie Hilfe bei der Formatierung Ihrer Beiträge.
      2. Hallo Matthias,

        im Beispiel-Kasten steht so etwas:

        <script src="extensions/Selfhtml/example.php/Beispiel:JS-Anw-FktPlot-fkt-plotter.js"></script>

        und der Name der Javascriptdatei verlinkt dann auf eben diese, so wie in der Quelltextansicht der Browser.

        Gruß
        Jürgen

        1. Hallo JürgenB,

          <script src="extensions/Selfhtml/example.php/Beispiel:JS-Anw-FktPlot-fkt-plotter.js"></script>

          und der Name der Javascriptdatei verlinkt dann auf eben diese, so wie in der Quelltextansicht der Browser.

          {{Beispiel|
          {{BeispielCode|bla}}
          {{BeispielText|1=
          * [[Beispiel:JS-Anw-FktPlot-fkt-plotter.js]]
          * [https://wiki.selfhtml.org/wiki/Beispiel:JS-Anw-FktPlot-fkt-plotter.js?action=render Beispiel:JS-Anw-FktPlot-fkt-plotter.js]}}
          }}
          

          Direkt im Code gehts wenn überhaupt nur über Umwege. Mal probieren. Und dann muss der Link auch noch als solcher erkennbar sein.

          Bis demnächst
          Matthias

          --
          Dieses Forum nutzt Markdown. Im Wiki erhalten Sie Hilfe bei der Formatierung Ihrer Beiträge.
          1. Hallo Matthias Apsel,

            Direkt im Code gehts wenn überhaupt nur über Umwege. Mal probieren.

            Geht auch

            {{Beispiel|
            {{BeispielCode|1=<nowiki><script src="</nowiki>[[Beispiel:JS-Anw-FktPlot-fkt-plotter.js]]<nowiki>"</script></nowiki>
            <nowiki><script src="</nowiki>[https://wiki.selfhtml.org/wiki/Beispiel:JS-Anw-FktPlot-fkt-plotter.js?action=render Beispiel:JS-Anw-FktPlot-fkt-plotter.js]<nowiki>"</script></nowiki>}}
            {{BeispielText|1=
            * [[Beispiel:JS-Anw-FktPlot-fkt-plotter.js]]
            * [https://wiki.selfhtml.org/wiki/Beispiel:JS-Anw-FktPlot-fkt-plotter.js?action=render Beispiel:JS-Anw-FktPlot-fkt-plotter.js]}}
            }}
            

            Allerdings nur ohne Syntaxhervorhebung.

            Bis demnächst
            Matthias

            --
            Dieses Forum nutzt Markdown. Im Wiki erhalten Sie Hilfe bei der Formatierung Ihrer Beiträge.