Matthias Scharwies: Manöverkritik: OOP in JS

Guten Morgen!

@Felix Riesterer hatte im Februar einen Einstieg in die OOP gestartet, der hier diskutiert wurde:

Molilys Artikel-Reihe "Organisation von JavaScripten" von 2006 wird dieses Jahr 15. Sie war auch nie als durchgängiger Kurs bestimmt.

Ich habe jetzt einmal eine überarbeitete Version veröffentlicht: JavaScript/Tutorials/OOP

  1. JavaScript/Tutorials/OOP/Einstieg
    • theoretisch; ohne Code
    • Infografik (Klasse-Konstruktor-Objektinstanzen) kommt noch
  2. JavaScript/Tutorials/OOP/Objekte und ihre Eigenschaften
    • kontextualisiert mit Personen
    • Live-Beispiele (um Änderungen gleich in der Konsole zu sehen)
    • Passen Kind-Objekte in den Aufbau oder sollte man sie streichen / woanders einsetzen?
  3. JavaScript/Tutorials/OOP/Klassen und Vererbung
    • integriert Felix Kapitel mit @Wiko s Änderungen und der prototypischen Vererbung
    • zuerst ES6, dann die prototypische V. aus ES3
  • JavaScript/Tutorials/OOP/Module und Kapselung
    • Einiges wie Unobtrusive JavaScript steht mittlerweile im Einstieg in JS; YUI und Mootools kennen nur noch die Älteren, ich würde es hier ebenso machen:
    • zuerst ES6 erklären, dann eben die konventionellen Sachen wie Revealing Module Pattern
    • Wie würdet ihr die Abgrenzung zu den anderen Kapiteln sehen?
    • static wird bereits bei Klassen und Vererbung gelistet.
    • Closures werden hier und im nächsten Kapitel bei this besprochen

Ich würde neben dem Einstieg im Kurs in sich geschlossene Kapitel wie this und Objektabfragen behalten; dazu könnte man noch Destrukturierung und Proxy (in @Rolf B s Benutzernamensraum) verlinken.

Ich frag euch heut abend mal am Stammtisch aus!

Herzliche Grüße

Matthias Scharwies

--
Einfach mal was von der ToDo-Liste auf die Was-Solls-Liste setzen.“
  1. Guten Morgen!

    1. JavaScript/Tutorials/OOP/Einstieg
      • Infografik (Klasse-Konstruktor-Objektinstanzen) kommt noch
    1. Wo soll die hin?
    2. Was soll an weiterem Text noch rein?

    OOP

    Ich würde evtl. über die Fabrik dann noch einen Prototypen legen.

    Herzliche Grüße

    Matthias Scharwies

    --
    Einfach mal was von der ToDo-Liste auf die Was-Solls-Liste setzen.“
  2. Hallo,

    sieht prima aus, Danke!

    In der Vorstellung des Konstruktors, fehlt da in der Funktion 'sayname' jeweils das 'this' bei den Namen?

    Gruß
    Kalk

    1. Servus!

      Hallo,

      sieht prima aus, Danke!

      In der Vorstellung des Konstruktors, fehlt da in der Funktion 'sayname' jeweils das 'this' bei den Namen?

      OOPs - danke!

      Herzliche Grüße

      Matthias Scharwies

      --
      Einfach mal was von der ToDo-Liste auf die Was-Solls-Liste setzen.“
  3. Lieber Matthias,

    Ich habe jetzt einmal eine überarbeitete Version veröffentlicht: JavaScript/Tutorials/OOP

    mir gefällt die Ausführlichkeit. Da ich mit keinem echten Anfänger beide Vorlagen anschauen und ausprobieren konnte, kann ich nicht sicher beurteilen, welche Ausführlichkeit an welcher Stelle welches Verständnis erleichtert. Mir fehlt es zur Zeit schlicht an geeigneten Lerngruppen, um das zu evaluieren.

    1. JavaScript/Tutorials/OOP/Klassen und Vererbung
      • integriert Felix Kapitel mit @Wiko s Änderungen und der prototypischen Vererbung
      • zuerst ES6, dann die prototypische V. aus ES3

    Mir fällt da etwas im Kapitel 1.2.2 Methoden für Events auf, das ich hier zur Diskussion stellen möchte.

    hit (event) {
        var classThis = this.self;
        return "Ich bin " + classThis._alter + " Jahre alt."
    }
    

    Hier soll offensichtlich ein Event verarbeitet werden. Soweit klar. Was mich stört, ist die Annahme, dass man diese Objektmethode zwingend so verwendet:

    object.addEventListener("click",p.click);
    

    Diese Einbindung hat tatsächlich das Problem, dass ich innerhalb der Objektmethode hit(event) ein Problem mit dem Schlüsselwort this habe. Meiner Meinung nach ist aber die beste Lösung eben nicht, in hit(event) mit this.self zu hantieren, sondern die Einbindung so vorzunehmen, dass es das überhaupt nicht erst braucht:

    class Person {
      constructor (name, alter) {...}
      hit (event) { return "Ich bin " + this._alter + " Jahre alt."; }
    }
    
    var p = new Person("Frizzy", 15);
    var object = document.getElementById("alter");
    object.addEventListener("click", event => p.hit(event));
    

    In altmodischerer Schreibweise wäre die letzte Zeile eher so:

    object.addEventListener("click", function (event) { p.hit(event); });
    

    Damit ist der this-Kontext in der Objektmethode von Person genau der, den man dort gerne haben möchte. Und das Kapitel "Methoden für Events" sollte eher "Umgang mit dem this-Kontext bei Verwendung von Events" lauten.

    Inwiefern man in einer Objektmethode this.self verwenden kann und wann man so etwas wirklich benötigt, ist eine andere Frage, die meiner Meinung nach an dieser Stelle das Anfängertutorial eher überfrachtet, als das Verständnis (wir sind inhaltlich noch immer ziemlich am Anfang!) zu stärken.

    Was meint ihr dazu?

    Liebe Grüße

    Felix Riesterer

    1. @@Felix Riesterer

      Mir fällt da etwas im Kapitel 1.2.2 Methoden für Events auf, das ich hier zur Diskussion stellen möchte.

      hit (event) {
          var classThis = this.self;
          return "Ich bin " + classThis._alter + " Jahre alt."
      }
      

      Da fällt mir noch was auf.

      Die umständliche, unübersichtliche Schreibweise mit String zusammenbasteln sollte nicht mehr verwendet werden, sondern ein template literal:

          return `Ich bin ${classThis._alter} Jahre alt.`;
      

      „Aber der IE!“„Shut up!“

      Noch besser: mit nicht umbrechendem Leerzeichen zwischen Zahl und Einheit:

          return `Ich bin ${classThis._alter}\u{A0}Jahre alt.`;
      

      😷 LLAP

      PS: Wer hat da code { overflow: scroll-x } ins Forum-Stylesheet eingebaut? Das sieht ja furchtbar aus.

      --
      „Dann ist ja auch schrecklich, dass wir in einem Land leben, in dem nicht nur Bildungswillige leben, sondern auch hinreichende Zahlen von Bekloppten. Das darf ich so locker formulieren, ich bin ja jetzt Rentner und muss nicht mehr auf jedes Wort achten.“
      — Joachim Gauck über Impfgegner
      1. Hallo Gunnar,

            return `Ich bin ${classThis._alter} Jahre alt.`;
        

        „Aber der IE!“„Shut up!“

        😀

        Noch besser: mit nicht umbrechendem Leerzeichen zwischen Zahl und Einheit:

            return `Ich bin ${classThis._alter}\u{A0}Jahre alt.`;
        

        Schöner is' das. Vor allem dann, wenn für die Einheit nur das Einheitenzeichen notiert wird. Hier, wo die Einheit als ganzes Wort ausgeschrieben ist, würde ich auch einen Umbruch verschmerzen.

        May the Schwartz be with you
         Martin

        --
        Theorie ist, wenn eigentlich jeder weiß, wie's gehen müsste, und es geht doch nicht.
        Praxis ist, wenn's geht, obwohl es keiner so richtig versteht.
        Bei uns sind Theorie und Praxis vereint: Nichts geht, und keiner weiß, warum.
        1. @@Der Martin

          Noch besser: mit nicht umbrechendem Leerzeichen zwischen Zahl und Einheit:

              return `Ich bin ${classThis._alter}\u{A0}Jahre alt.`;
          

          Schöner is' das. Vor allem dann, wenn für die Einheit nur das Einheitenzeichen notiert wird.

          In dem Falle wäre ein schmales nicht umbrechendes Leerzeichen angebracht:

              return `Ich bin ${classThis._gewicht}\u{202F}kg schwer.`;
          

          Siehe Codepen: Hobbits (gezeigt in diesen Vortrag)

          😷 LLAP

          PS: Mir ist der Unterschied zwischen Masse und Gewicht bewusst. Ich wollte es hier nicht zu schwer machen. (No pun intended.)

          --
          „Dann ist ja auch schrecklich, dass wir in einem Land leben, in dem nicht nur Bildungswillige leben, sondern auch hinreichende Zahlen von Bekloppten. Das darf ich so locker formulieren, ich bin ja jetzt Rentner und muss nicht mehr auf jedes Wort achten.“
          — Joachim Gauck über Impfgegner
          1. Hallo Gunnar,

            In dem Falle wäre ein schmales nicht umbrechendes Leerzeichen angebracht:

            gibt es inzwischen Browser, die das auch schmal anzeigen?

            Gruß
            Jürgen

            1. @@JürgenB

              gibt es inzwischen Browser, die das auch schmal anzeigen?

              Öhm, ja:

              Siehe Codepen: Hobbits

              Und das Problem sind wohl nicht Browser, sondern dass die verwendeten Fonts auch tatsächlich eine Glyphe für U+202F bereitstellen – und zwar eine mit anderer Breite als für U+0020/U+00A0.

              😷 LLAP

              --
              „Dann ist ja auch schrecklich, dass wir in einem Land leben, in dem nicht nur Bildungswillige leben, sondern auch hinreichende Zahlen von Bekloppten. Das darf ich so locker formulieren, ich bin ja jetzt Rentner und muss nicht mehr auf jedes Wort achten.“
              — Joachim Gauck über Impfgegner
              1. Hallo Gunnar,

                gibt es inzwischen Browser, die das auch schmal anzeigen?

                Öhm, ja:

                Siehe Codepen: Hobbits

                Und das Problem sind wohl nicht Browser, sondern dass die verwendeten Fonts auch tatsächlich eine Glyphe für U+202F bereitstellen – und zwar eine mit anderer Breite als für U+0020/U+00A0.

                betrachtet im iPhone und am W10-PC mit dem FF 78.10.0esr und mit dem Chrome 96: ich sehe keinen Unterschied 😟.

                Gruß
                Jürgen

                1. @@JürgenB

                  betrachtet im iPhone und am W10-PC mit dem FF 78.10.0esr und mit dem Chrome 96: ich sehe keinen Unterschied 😟.

                  Mir dämmert’s: Ich hatte den Codepen ja erstellt, um ihn bei besagtem Vortrag zu zeigen. Als Schrift verwende ich Fira Sans, die habe ich auch lokal installiert. Du vermutlich nicht, deshalb wird’s bei dir in einer anderen Schriftart gerendert, wo womöglich kein Unterschied zwischen normalbreitem und schmalem Leerzeichen ist.

                  Bei mir sieht’s (bei entsprechender Viewportbreite) so aus:

                  Screenshot

                  Muss wohl nochmal nachlesen, wie man Webfonts in CodePen nutzen kann.

                  😷 LLAP

                  --
                  „Dann ist ja auch schrecklich, dass wir in einem Land leben, in dem nicht nur Bildungswillige leben, sondern auch hinreichende Zahlen von Bekloppten. Das darf ich so locker formulieren, ich bin ja jetzt Rentner und muss nicht mehr auf jedes Wort achten.“
                  — Joachim Gauck über Impfgegner
                  1. @@Gunnar Bittersmann

                    Als Schrift verwende ich Fira Sans, die habe ich auch lokal installiert. Du vermutlich nicht, deshalb wird’s bei dir in einer anderen Schriftart gerendert, wo womöglich kein Unterschied zwischen normalbreitem und schmalem Leerzeichen ist. […]

                    Muss wohl nochmal nachlesen, wie man Webfonts in CodePen nutzen kann.

                    Wird der Pen jetzt auch bei euch in Fira Sans gesetzt?

                    😷 LLAP

                    --
                    „Dann ist ja auch schrecklich, dass wir in einem Land leben, in dem nicht nur Bildungswillige leben, sondern auch hinreichende Zahlen von Bekloppten. Das darf ich so locker formulieren, ich bin ja jetzt Rentner und muss nicht mehr auf jedes Wort achten.“
                    — Joachim Gauck über Impfgegner
                    1. Hallo Gunnar,

                      auf meinem iPhone sind die schmalen Leerzeichen jetzt schmal.

                      Gruß
                      Jürgen

                    2. Hallo Gunnar,

                      ... Fira Sans ...?

                      ich habe mir gerade die Tabelle zum Sortierer im Wiki angesehen. Die Seite ist in Helvetica gesetzt, und in meinem Safari werden die Tausendertrenner schmal angezeigt.

                      Gruß
                      Jürgen

    2. Hallo Felix,

      Was meint ihr dazu?

      (1) Sowohl Wiki als auch Du sind im Irrtum mit der Aussage, dass das this-Objekt in diesem Fall das Eventobjekt ist. Das Eventobjekt wird grundsätzlich als Parameter übergeben. Der Wert von this hängt von der Art der Registrierung ab.

      Das ist in einer unheiligen Allianz von DOM und WebIDL Spec exakt festgelegt. Die WebIDL Spec hat einen Abschnitt "Call a user object's operation", die den Umgang mit einem Callback festlegt, und in der DOM Spec steht, dass beim Aufruf eines Eventlisteners für das registrierte Eventlistener-Objekt "call a user object's operation" mit der Operation "handleEvent", Argument "event-Objekt" und thisArg "currentTarget" auszuführen sei. Und in der WebIDL Spec steht dann, dass das Objekt entweder "Callable" sein kann oder ein Objekt mit einer Eigenschaft, die dem Operationsnamen entspricht. Im zweiten Fall wird thisArg durch das EventListener-Objekt ersetzt (WEBIDL 3.11, call a user object's operation, Step 10).

      Demnach: Registriert man eine Funktion, enthält this den Wert von event.currentTarget (identisch mit dem Objekt, auf dem der Listener registriert wurde). Registriert man ein EventListener-Objekt, enthält this dieses Objekt.

      Das ist auch sinnvoll, denn andernfalls käme man in der handleEvent-Methode nicht an die übrigen Eigenschaften des EventListener-Objekts heran.

      Ich habe das vor ein paar Tagen auch hier notiert.

      Was mich stört

      Mich auch. Und dazu stört mich so einiges mehr.

      (1) Anerkannte Application Patterns werden ignoriert

      • Person ist Model, nicht ViewModel, da gehören keine Handler für Klicks hin
      • Das click-Objekt der Person legt die Reaktion des Objekts auf einen Klick fest. Wie ein UI-Ereignis zu behandeln ist, entscheidet im MVVM Pattern der View und bei MVC der Controller. Nicht das ViewModel, nicht das Model.

      (2) Verletzung von SRP (Single Responsibility Principle).

      • Die hit-Methode muss sich um zwei verschiedene Dinge kümmern: Ermitteln des richtigen this und Behandeln des Click-Events. Das ist falsch.

      (3) Schlechte Namensgebung. Wieso heißt eine Methode, die das Alter anzeigt, "hit", und nicht "zeigeAlter"?

      (4) Ich würde gerne eine Klarstellung haben - außerhalb des Wikis - ob ein EventListener Objekt noch Stand der Technik ist. Dieses Interface findet sich bereits im DOM Level 2 von 2003. Seitdem wurde die bind-Methode (ECMAScript 5.1, 2011) und Pfeilfunktionen (ECMAScript 2015) eingeführt, die das Problem ebenfalls lösen können und es - meine ich - eleganter tun.

      MDN schreibt:

      Note: Due to the need for compatibility with legacy content, EventListener accepts both a function and an object with a handleEvent() property function.

      Angesichts der obigen Zeitleiste ist das Objekt mit handleEvent() Property die Legacy, nicht die Funktion. Wollen wir etwas promoten, das zwecks "compatibility with legacy content" existiert?

      Die Pfeilfunktion wurde bereits von Felix gezeigt. Mit bind sähe es so aus:

      object.addEventListener("click", p.zeigeAlter.bind(p));
      

      und natürlich gibt's auch die gute alte function-Expression als Fallback.

      Bind statt Pfeilfunktion hat eine Existenzberechtigung für Seiten, die Altbrowser unterstützen wollen/müssen. In Browsern, die bind nicht unterstützen, sollte man sich JavaScript besser nicht antun…

      Aus meiner Sicht ist ein eventListener-Objekt dann und nur dann sinnvoll, wenn man ein bestimmtes Event unabhängig von einem Modellobjekt behandeln will, und eine Funktion dafür nicht ausreicht. Dafür kann es viele Anlässe geben. Aber zur reinen Delegation eines Events an eine Objektmethode ist es der falsche Ansatz, weil es dafür mittlerweile standardisierte Möglichkeiten gibt.

      Rolf

      --
      sumpsi - posui - obstruxi
      1. Hallo Rolf,

        Überarbeitet: https://wiki.selfhtml.org/wiki/JavaScript/Tutorials/OOP/Objekte_und_ihre_Eigenschaften#this

        Rolf

        --
        sumpsi - posui - obstruxi
      2. Hallo Rolf,

        Konstruktoren überarbeitet, Abschnitt über Prototypen hinzugefügt.

        Da stand einiges, was falsch war. Dass Prototypen ein Bauplan sind und das Instanzobjekt eine Kopie des Prototypen - nein. Definitiv nein. Die Bauplanmetapher gilt für Klassen der OOP, aber nicht für Prototypen.

        Die Umleitung für [[Prototyp]] und [[Prototype]] könnte nun auf das Prototyp-Kapitel dieses Artikels zeigen. Die aktuelle Zielposition ist ja ohnehin auf der Kippe.

        Rolf

        --
        sumpsi - posui - obstruxi
    3. Hallo,

      Mir fällt da etwas im Kapitel 1.2.2 Methoden für Events auf, das ich hier zur Diskussion stellen möchte.

      ich muss zu meiner Schande gestehen, das ich in diesem Unterkapitel zwar das this-Problem, sonst aber nichts verstanden habe.

      Was macht

      this.click = {handleEvent:this.hit, self:this};
      

      und warum wird die Methode click im constructor definiert?

      Wer bearbeitet den return-Wert von hit?

      Gruß
      Jürgen

      1. Lieber JürgenB,

        ich muss zu meiner Schande gestehen, das ich in diesem Unterkapitel zwar das this-Problem, sonst aber nichts verstanden habe.

        Was macht

        this.click = {handleEvent:this.hit, self:this};
        

        und warum wird die Methode click im constructor definiert?

        das ist mir auch sehr schleierhaft. In meinen Projekten hätte ich die Methode hit so gestaltet, dass sie wie jede andere Methode der Klasse auch von einem this ausgehen kann, welches auf die Objektinstanz zeigt. Um das zu erreichen verwende ich addEventListener entsprechend:

        node.addEventListener("click", event => myObject.myMethod(event));
        

        Wer bearbeitet den return-Wert von hit?

        Der landet im digitalen Nirvana. Offensichtlich ist die Überarbeitung noch in vollem Gange, sodass wir beide einfach abwarten sollten, bis eine endgültige (oder "Meilenstein"-) Fassung erreicht ist. Dann wird uns das Beispiel sicher sofort einleuchten.

        Liebe Grüße

        Felix Riesterer

        1. Hallo Felix,

          ich beschäftige mich gerade mit Pointerevents, und da mit vielen Pointern. Um mit den diversen Eventhandlern und dem Eventcache nicht zu viele globale Objekte zu haben, habe ich alles in einer Klasse gebündelt. Das this-Problem habe ich erst mal mit der Pfeilfunktion gelöst.

          Meiner Meinung nach gehören in dieses Tutorial aber auch noch Setter und Getter.

          Gruß
          Jürgen

          1. Servus!

            Hallo Felix,

            ich beschäftige mich gerade mit Pointerevents, und da mit vielen Pointern. Um mit den diversen Eventhandlern und dem Eventcache nicht zu viele globale Objekte zu haben, habe ich alles in einer Klasse gebündelt. Das this-Problem habe ich erst mal mit der Pfeilfunktion gelöst.

            Meiner Meinung nach gehören in dieses Tutorial aber auch noch Setter und Getter.

            Ja, @Rolf B hat(te) die schon in seinem Entwurf drin:

            Herzliche Grüße

            Matthias Scharwies

            --
            Einfach mal was von der ToDo-Liste auf die Was-Solls-Liste setzen.“
      2. Hallo JürgenB,

        Was macht this.click = {handleEvent:this.hit, self:this}; und warum wird die Methode click im constructor definiert?

        Da wird keine Methode definiert. Da wird ein Objekt erzeugt, das die EventListener-Schnittstelle implementiert. Das ist Technik von anno Tobak, wie ich hier schon schrub und die Relevanz befragte. Warum "Methoden für Events" in dem Kapitel stehen, ist ohnehin fragwürdig, diese Diskussion gehört generell zu Methoden und this.

        Einerseits habe ich das [hier](und warum wird die Methode click im constructor definiert?) angerissen, das kann man ggf. noch vertiefen, und andererseits kann man das im Zusammenhang mit addEventListener nochmal ausführen.

        Dieses Objekt kann dann von einem Nutzer des Objekts verwendet werden, um ein click-Event von diesem Objekt behandeln zu lassen. Was ich in der gezeigten Form architektonisch missbillige und im oben verlinkten Beitrag ebenfalls schreibte.

        Im übrigen verhält sich der Ablauf fast genauso, als ob man eine Funktion als Event Listener verwenden würde, d.h. was mit dem Rückgabewert gemacht wird, steht nicht in der Spec. Aber traditionell, aus Zeiten vor DOM Level 2, wird return false wie event.preventDefault() behandelt. Meine ich...

        Es ist fast genauso, weil das this unterschiedlich ist. Ein Funktions-Eventlistener bekommt event.currentTarget als this und ein Objekt-Eventlistener bekommt das Objekt als this.

        Quelle: DOM Spec, inner invoke Schritt 10, und dann WebIDL Spec, Schritt 9 und 10.

        Rolf

        --
        sumpsi - posui - obstruxi
        1. Hallo Rolf,

          ich habe mal etwas recherchiert und diese Lösung gefällt mir am besten:

          class Pointerevents {	
            constructor(pointertarget) {
              pointertarget.addEventListener("pointerdown",  this.down , false);
              ...
            }
          	
            down = (event) => this.handledown(event);
            handledown(event) {
              const id = event.pointerId;
              event.preventDefault();
              this.pointereventcache[id] = event;
              ...
            } // down
            ...
          }
          new Pointerevents(document.body);
          

          Bei dieser Variante können die Eventhandler auch wieder entfernt werden.

          Gruß
          Jürgen

          1. Lieber JürgenB,

            pointertarget.addEventListener("pointerdown",  this.down , false);  
            ...  
            down = (event) => this.handledown(event);  
            handledown(event) { ... }
            

            da bin ich mir nicht sicher, ob die "lokale Funktion" (oder "nur" eine Closure?) namens down in dieser Klassensyntax nicht einen Fehler wirft. Meiner Erinnerung nach ist innerhalb der Klassensyntax ein implizites "use strict" enthalten, welches vor down ein let|const|var erfordert.

            Warum nicht gleich so?

            pointertarget.addEventListener(
              "pointerdown",
              event => this.handledown(event),
              false
            );
            

            Liebe Grüße

            Felix Riesterer

            1. Hallo Felix,

              Lieber JürgenB,

              pointertarget.addEventListener("pointerdown",  this.down , false);  
              ...  
              down = (event) => this.handledown(event);  
              handledown(event) { ... }
              

              da bin ich mir nicht sicher, ob die "lokale Funktion" (oder "nur" eine Closure?) namens down in dieser Klassensyntax nicht einen Fehler wirft. Meiner Erinnerung nach ist innerhalb der Klassensyntax ein implizites "use strict" enthalten, welches vor down ein let|const|var erfordert.

              das ist so im Einsatz. Ein let|const|var vor dem down würde einen Fehler werfen. Variablen dürfen in Klassen nur innerhalb von Methoden deklariert werden.

              Warum nicht gleich so?

              pointertarget.addEventListener(
                "pointerdown",
                event => this.handledown(event),
                false
              );
              

              so kann man den Eventhandler nicht entfernen. Und ob der Handler innerhalb der Klasse oder außerhalb registriert wird, hängt von der Anwendung ab bzw. ist Geschmacksache.

              Gruß
              Jürgen

              1. Hallo JürgenB,

                Und ob der Handler innerhalb der Klasse oder außerhalb gegistriert wird, hängt von der Anwendung ab bzw. ist Geschmacksache.

                Ob nun re- oder gegistriert, Geschmackssache sollte das nur ausnahmsweise sein. Die SOLID Prinzipien dürften in den meisten Fällen klare Richtlinien liefern, wo eine Eventregistrierung hingehört und wo nicht.

                Rolf

                --
                sumpsi - posui - obstruxi
                1. Hallo Rolf,

                  Ob nun re- oder gegistriert,

                  grrrrr. Hab das mal korrigiert.

                  Geschmackssache sollte das nur ausnahmsweise sein. Die SOLID Prinzipien dürften in den meisten Fällen klare Richtlinien liefern, wo eine Eventregistrierung hingehört und wo nicht.

                  OK

                  Gruß
                  Jürgen

            2. Hallo Felix,

              nein, das funktioniert. Das ist die korrekte Syntax zum Definieren von Instanzproperties. Mit static davor wäre es ein Klassenproperty.

              Die Syntax ist allerdings neu. Brandneu. Kangax listet es als ES2022 Feature, das seit Ende 2020 ziemlich breit unterstützt wird, mit Nachzügler Firefox (ab v90).

              Man kann das also mittlerweile empfehlen.

              Rolf

              --
              sumpsi - posui - obstruxi
              1. Hallo Rolf,

                Die Syntax ist allerdings neu. Brandneu. Kangax listet es als ES2022 Feature, das seit Ende 2020 ziemlich breit unterstützt wird, mit Nachzügler Firefox (ab v90).

                der 78.10.0.esr auf meinem Dienstrechner unterstützt es auch schon.

                Gruß
                Jürgen

                1. Hallo JürgenB,

                  78.10.0.esr

                  stimmt, habe nicht gesehen dass Kangax die FF vor 90 als "partiell" auflistet und die Partialität sich darauf bezieht, dass nur die private instance properties fehlen. FF78 ist laut en-Wikipedia von Mitte '20, also on par mit den anderen Browsern.

                  Rolf

                  --
                  sumpsi - posui - obstruxi
  4. Hallo Matthias,

    ich stolpere nochmal über die Unterobjekte.

    Ich weiß, dass man hier an einem sehr frühen Punkt ist, aber trotzdem müsste man eigentlich zwischen abhängigen und unabhängigen Objektbeziehungen unterscheiden. Um beim Beispiel zu bleiben: Ein Baby ist - vor der Geburt - von seiner Mutter abhängig - kommt der erwähnte Bus, sind beide tot. Die Mutter könnte aber auch ein Objekt "Handtasche" haben, mit Inhalten wie Ausweis, Autoschlüssel und Pfefferspray. Besagter Bus kann die Mutter töten, aber die Handtasche existiert als Objekt weiter. In beiden Fällen liegt eine Assoziation vor, aber das Baby ist vom Typ Komposition ("Y is-part-of X") und die Handtasche vom Typ Aggregation ("X has-a Y"). Das Baby ist deshalb auch ein interessantes Beispiel, denn ab einem gewissen Moment wechselt es seine Assoziationsart von part-of zu has-a.

    So richtig problematisch ist an dieser Stelle der Scope. Objektbeziehungen erschaffen keinen Scope - das passiert beim Schachteln von Funktionen. Eine Funktion Y, die innerhalb einer Funktion X definiert wird, kann auf die Daten von X zugreifen (was eine grobe Vereinfachung darstellt, mit Details schmeißt das Wiki beim Them Closures um sich). Bei Eltern- und Kindobjekt dagegen kommt es darauf an, welche Verknüpfung erzeugt worden ist. Wenn die Mutter ein Property "baby" enthält, kann die Mutter auf das Kindobjekt zugreifen. Das Kind kann damit existieren, ohne etwas von der Mutter zu wissen. Wenn das Kindobjekt ein Property "mother" bekommt, kann es auch auf seine Mutter zugreifen. Das ist was ganz anderes.

    Eine gute Formulierung für den Abschnitt habe ich noch nicht; ich muss jetzt erstmal weg und denke später nochmal drüber nach.

    Rolf

    --
    sumpsi - posui - obstruxi
    1. Hallo Rolf,

      ich würde den ganzen Abschnitt am liebsten durch dies hier ersetzen, bin damit aber noch nicht ganz zufrieden.

      Rolf

      --
      sumpsi - posui - obstruxi
      1. Servus!

        1. JavaScript/Tutorials/OOP/Objekte und ihre Eigenschaften
          • kontextualisiert mit Personen
          • Live-Beispiele (um Änderungen gleich in der Konsole zu sehen)
          • Passen Kind-Objekte in den Aufbau oder sollte man sie streichen / woanders einsetzen?

        ich würde den ganzen Abschnitt am liebsten durch dies hier ersetzen, bin damit aber noch nicht ganz zufrieden.

        Für mich sieht's gut aus. Die (evtl. doppelt vorhandenen) Adressen sind auch eine gute Idee.

        Ich weiß aber nicht, wie viel ins erste Praxis-Kapitel passt (jetzt sind noch Prototypen dabei).

        Evtl. sollten wir es eben auf mehrere, thematisch getrennte Kapitel aufteilen. Nicht alles muss im ersten Kapitel in der ersten Stunde behandelt werden.

        Herzliche Grüße

        Matthias Scharwies

        --
        Einfach mal was von der ToDo-Liste auf die Was-Solls-Liste setzen.“
        1. Dieser Beitrag wurde gelöscht: Der Beitrag ist ein Duplikat eines anderen Beitrags.
        2. Hallo Matthias,

          ja, guter Plan. Eigenschaften und Methoden in Objekten ohne Konstruktoren, dann Konstruktoren und Prototypen, dann Objektbeziehungen. Das sind 3 nicht zu lange Artikel, und man kann sie ggf. ausbauen.

          Ich würde DANN aber bei Objekte und Eigenschaften noch einen Abschnitt anfügen wollen, als "optionale Lektüre", der auf defineProperty eingeht, womit man readonly-Properties sowie getter und setter erzeugen kann.

          Rolf

          --
          sumpsi - posui - obstruxi
          1. Hallo Rolf,

            Ich würde DANN aber bei Objekte und Eigenschaften noch einen Abschnitt anfügen wollen, als "optionale Lektüre", der auf defineProperty eingeht, womit man readonly-Properties sowie getter und setter erzeugen kann.

            ich bin ja froh, dass du das als optionale Lektüre einordnest. Denn ich halte mich selbst nicht für ganz ahnungslos in Javascript (also nicht Fußgänger, mindestens schon Radfahrer), aber das ist dann auch für mich schon relativ schwere Kost.

            May the Schwartz be with you
             Martin

            --
            Theorie ist, wenn eigentlich jeder weiß, wie's gehen müsste, und es geht doch nicht.
            Praxis ist, wenn's geht, obwohl es keiner so richtig versteht.
            Bei uns sind Theorie und Praxis vereint: Nichts geht, und keiner weiß, warum.
        3. Hallo Matthias,

          ich hatte jetzt drei Stunden lang im Objekte+Eigenschaften Artikel etliche Änderungen vorgenommen, ohne zwischenzuspeichern. Kann man ja nicht, ohne zu veröffentlichen. Und jedesmal einen Artikel in den Userspace zu legen ist lästig. Dem Wiki fehlt eine "Autosave Draft" Funktion, wie im Forum.

          Denn: wie es mir REGELMÄSSIG irgendwann passiert - ich bin irrtümlich auf Strg+W gekommen und das Browsertab geht ohne Rückfrage zu. Beim Close eines Tab fragt er ja wenigstens rück, aber Strg+W ist der ultimative Boss-Key. Der Idiot, der das festgelegt hat, gehört einen Kopf kürzer gemacht, und zwar an den Füßen, damit er was davon hat! Diese Taste ist viel zu schnell irrtümlich erwischt.

          Für Chrome habe ich jetzt den Tipp gefunden, nach chrome://extensions zu gehen und die Tastenkombination einer Extension zuzuweisen, die nicht relevantes tut. Bei mir ist es der Google Drive Anwendungslauncher. Und Strg+W ist wirklungslos. Endlich.

          Oh! Nachtrag: Strg+Shift+T - reopen closed tab. Klappt auch mehrfach, und hat mich gerettet. Hatte ich vorhin probiert, aber per Maus im Menü, und nur den Stand VOR meiner Bearbeitung gefunden.

          D.h. mein Text ist wieder da, und steht auf meiner Benutzerseite unter Benutzer:Rolf B/Objekte.

          Was ich eigentlich wissen wollte: welche Herkunft hat der aktuelle Text eigentlich? Ist das von Wiko, und wenn ich darin grob ändere, fange ich mir Ärger ein? Oder ist es alter Molily Text und Freiwild?

          Rolf

          --
          sumpsi - posui - obstruxi
          1. Lieber Rolf!

            D.h. mein Text ist wieder da, und steht auf meiner Benutzerseite unter Benutzer:Rolf B/Objekte.

            Der sieht gut aus, …

            Was ich eigentlich wissen wollte: welche Herkunft hat der aktuelle Text eigentlich? Ist das von Wiko, und wenn ich darin grob ändere, fange ich mir Ärger ein? Oder ist es alter Molily Text und Freiwild?

            Das ist, wie ich oben oben geschrieben hatte, von mir.

            Ich hatte im März/Mai 2016 ja schon einmal angefangen, den Molily-Text durch eine eigene Variante zu ersetzen. Damals hatten parallel @Orlok JavaScript/Objekte/Object und Du Benutzer:Rolf_b/tempObjekteEigenschaften entwickelt, in den ich immer wieder reinschaue.

            In der Neufassung vom August 2020, die ich nur im Test-Wiki angefangen hatte und die durch Felix' OOP-Tutorial im Feb 2021 dort erst mal liegengeblieben war, wollte ich zeigen, wie man mit der Konsole eben gleich untersuchen kann, wie Objekte aufgebaut sind. Das habe ich in einem Tutorial / Blog-Post bei Dillion Megida gesehen, das ich auch als Fußnote verlinkt habe.

            Ich hatte versucht den Spagat zu schaffen. Objekte richtig zu erklären und das Unnötige wegzulassen, bzw Grundlagen, die bereits in den Anfänger-Tutorials stehen, passend zu verlinken.

            Was ich nicht in ein Fortgeschrittenen-Tutorial einbauen würde, wäre die Diskussion const oder let, die ich als Fußnote erwähnt habe, sowie die Arbeit mit der Konsole / Console, die ja im Kurs Einstieg in JavaScript erklärt wird. [1]


            Wiko hat Felix' Klassen_und_Vererbung überarbeitet und durch Methoden_für_Events erweitert. Er möchte dort auch weitermachen.


            Was mir am ganzen Kurs noch fehlt, ist neben den Erklärungen ein Projekt, das man zusammen mit dem Leser entwickelt. Da hatte ich seit 2016 eben einen Vokabeltrainer im Auge, dessen JSON-Struktur dann auch erklärt worden wäre. So hätte man einen roten Faden und wäre nicht versucht, alle Alternativen in den Text zu integrieren.

            Da jetzt die molily-Texte im Kurs integriert sind, um Dopplungen zu vermeiden, werde ich (aber erst zum Jahreswechsel) ein Autorennen programmieren.

            Früher ging sowas mit Benzin, heute wohl eher mit Akku und Super-Charger. Im Netz geht alles mit canvas; evtl. kann man wenigstens die Autos und den Hintergrund mit SVG bauen.

            function Auto(startpos, benzin, startgeschwindigkeit)
            {
              this.s = startpos;
              this.benzin = benzin;
              this.v = startgeschwindigkeit;
            }
            

            Herzliche Grüße

            Matthias Scharwies

            --
            Einfach mal was von der ToDo-Liste auf die Was-Solls-Liste setzen.“

            1. Dieses Tutorial ist oben in der {{Vorlage:Text-Info}} als vorausgesetztes Wissen verlinkt. Der Link auf [[Seiteninspektor]] im Text führt auf Grundlagen/Webprojekte/testen, wo der Seiteninspektor erst im 3. Absatz und da nur für HTML erklärt wird. Das könnte/sollte man ändern. ↩︎

          2. @@Rolf B

            Denn: wie es mir REGELMÄSSIG irgendwann passiert - ich bin irrtümlich auf Strg+W gekommen und das Browsertab geht ohne Rückfrage zu.

            Passiert mir auch desöfteren. Bei mir ist [alt][shift][W] die Tastenkombination fürs öffnende Anführungszeichen „. Wenn ich statt [alt] das daneben liegende [cmd] erwische, ist nicht nur das Browsertab weg ([cmd][W]), sondern wegen [shift] gleich das ganze Browserfenster. 🤬

            😷 LLAP

            --
            „Dann ist ja auch schrecklich, dass wir in einem Land leben, in dem nicht nur Bildungswillige leben, sondern auch hinreichende Zahlen von Bekloppten. Das darf ich so locker formulieren, ich bin ja jetzt Rentner und muss nicht mehr auf jedes Wort achten.“
            — Joachim Gauck über Impfgegner
          3. Moin,

            Denn: wie es mir REGELMÄSSIG irgendwann passiert - ich bin irrtümlich auf Strg+W gekommen und das Browsertab geht ohne Rückfrage zu. Beim Close eines Tab fragt er ja wenigstens rück, aber Strg+W ist der ultimative Boss-Key. Der Idiot, der das festgelegt hat, gehört einen Kopf kürzer gemacht, und zwar an den Füßen, damit er was davon hat! Diese Taste ist viel zu schnell irrtümlich erwischt.

            wenn du den gefunden hast, sag Bescheid! Dann sammle ich ein paar Kilo Katzendreck.
            Ehrlich, so eine dämliche Idee! Dafür gibt's doch seit ewigen Zeiten schon Ctrl-F4.

            May the Schwartz be with you
             Martin

            --
            Theorie ist, wenn eigentlich jeder weiß, wie's gehen müsste, und es geht doch nicht.
            Praxis ist, wenn's geht, obwohl es keiner so richtig versteht.
            Bei uns sind Theorie und Praxis vereint: Nichts geht, und keiner weiß, warum.