Silke Seide: Objekt in Array so zulässig?

0 47

Objekt in Array so zulässig?

Silke Seide
  • javascript
  1. 0
    pl
    1. 0
      Silke Seide
  2. 0
    dedlfix
    1. 0
      ursus contionabundo
      1. 0
        dedlfix
        1. 0
          pl
          1. 0
            dedlfix
            1. 0
              pl
              1. 5
                Orlok
                • javascript
                • programmiertechnik
                1. 0
                  ursus contionabundo
                  1. 0
                    pl
                    1. 0
                      beatovich
                      1. 0
                        pl
                  2. 0
                    mark
                  3. 0
                    dedlfix
                    1. 0
                      Christian Kruse
                      1. 0
                        dedlfix
                        1. 0
                          Christian Kruse
                          1. 0
                            dedlfix
                            1. 0
                              Christian Kruse
                              1. 0
                                dedlfix
                                1. 0
                                  Christian Kruse
                                  1. 0
                                    1unitedpower
                                    1. 0
                                      1unitedpower
                                2. 2
                                  Rolf B
                                  1. 0
                                    Christian Kruse
                                  2. 0
                                    dedlfix
                                    1. 0
                                      Christian Kruse
                                      1. 0
                                        dedlfix
                                        1. 0
                                          Christian Kruse
                                    2. 0
                                      Rolf B
                              2. 0
                                dedlfix
                                1. 0
                                  Christian Kruse
                      2. 3
                        Christian Kruse
                        1. 0
                          dedlfix
                          1. -1
                            pl
                          2. 0
                            ursus contionabundo
                            1. 1
                              dedlfix
                        2. 0
                          Rolf B
                  4. 0
                    1unitedpower
                2. 0
                  1unitedpower
        2. 0
          ursus contionabundo
          1. 0
            pl
            1. 0

              Alter Perl-Pseudohash in modernem JS ...

              ursus contionabundo
              • javascript
              • meinung
              1. 0
                pl
    2. 0
      Silke Seide

Hallo,

ich hätte da eigentlich nur eine kurze Verständnisfrage:

ist es zulässig bzw. wohlgeformter Code, ein Objekt in einem Array wie folgt zu kreieren?

var Objekt_in_Array = [];
var ich_bin_ein_Objekt_Index = /*ich bin Objekt-value*/ Math.max(1, 2, 3);
// Semantik der folgenden Zeile zulässig?
Objekt_in_Array.push({ich_bin_ein_Objekt_Index});

Wenn nicht, wie würde ich vorgehen?

Erwünschtes Resultat ist, wie unschwer zu erkennen:

Objekt_in_Array = [{ich_bin_ein_Objekt_Index: 3}]

😂

Vielen Dank! S.

  1. Selbstverständlich! Guck Dir mal die TE Mustache.js an, die arbeitet mit genau einer solchen Datenstruktur (Loops für <table>, <ul>, <dl> usw.).

    MfG

    1. Alles klar 👍

      Danke! 😀

  2. Tach!

    ist es zulässig bzw. wohlgeformter Code, ein Objekt in einem Array wie folgt zu kreieren?

    Das sind zwei Teilfragen, die eine ist, dass man seit ES2015 Variablen bei der literal notation angeben kann, wobei der Variablenname als Eigenschaftsname genommen wird und der Inhalt als Wert.

    Auch der zweite Teil, Objekte in ein Array zu pushen, ist eine korrekte Vorgehensweise.

    dedlfix.

    1. ist eine korrekte Vorgehensweise.

      i.m.h.o. "syntaktisch korrekt". Ich würde den Verwender verbal verprügeln weil so was "nicht lesbar" ist.

      1. Tach!

        ist eine korrekte Vorgehensweise.

        i.m.h.o. "syntaktisch korrekt". Ich würde den Verwender verbal verprügeln weil so was "nicht lesbar" ist.

        Beziehst du dich auf den ersten Teil oder den zweiten?

        Wenn du den ersten meinst, dann finde ich (abgesehen von sprechenden Variablennamen)

        var o = {a: a, b: b, c: c};
        

        nicht wesentlich lesbarer als

        var o = {a, b, c};
        

        "Ich kenne diese Syntax nicht" gilt dabei nicht als Argument.

        dedlfix.

        1. Was soll das sein:

          var o = {a, b, c};
          

          "Ich kenne diese Syntax nicht" gilt dabei nicht als Argument.

          Bei mir erzeugt das ne Fehlermeldung.

          1. Tach!

            Was soll das sein:

            var o = {a, b, c};
            

            "Ich kenne diese Syntax nicht" gilt dabei nicht als Argument.

            Wie ich schrieb, das ist ES2015-Syntax.

            Bei mir erzeugt das ne Fehlermeldung.

            Verfügbar in Browsern seit: Chrome 47, Edge, Firefox 33, Safari 9.

            dedlfix.

            1. Wozu soll das gut sein?

              PS: Habs verstanden, is ja grausig. Gabs übrigens auch mal in Perl sowas, ist mittlerweile deprecated.

              Nichts verpasst.

              1. Hallo

                var o = {a, b, c};
                

                Wozu soll das gut sein?

                Das macht den Code besser lesbar und verringert die Wahrscheinlichkeit von Programmierfehlern.

                Schauen wir uns ein Beispiel ohne Shorthand Property Names an:

                // First declare some constants
                
                const a = 1, b = 2, c = 3;
                
                
                // Then initialize object with properties
                
                const object = {
                    a: a,
                    b: b,
                    c: c
                };
                

                Hier muss für jede Eigenschaftsdefinition der Name der Variable oder Konstante zweimal notiert werden, einmal als Eigenschaftsname und einmal zur Referenzierung des Wertes.

                Handelt es sich wie hier nur um Bezeichner bestehend aus einem Buchstaben, dann ist das kein Problem. Es ist aber in den seltensten Fällen angemessen, solche Bezeichner zu verwenden. In aller Regel möchte man aus Gründen der besseren Lesbarkeit längere, sprechende Variablennamen notieren.

                // More realistic declaration
                
                const aLongAndDescriptiveIdentifier = 'value';
                
                
                // Object initializer
                
                const object = {
                    aLongAndDescriptiveIdentifier: aLongAndDescripitveIdentifier
                };
                

                Das obige Beispiel ist kaputt. Siehst du den Fehler?

                Bei der Definition der Eigenschaft innerhalb des Objektliterals wurde zwar der Name der Eigenschaft richtig geschrieben, aber bei der Wiederholung des Bezeichners hat sich ein Buchstabendreher eingeschlichen.

                Die Ausführung des Programms wird mit einem ReferenceError abgebrochen.

                Dabei ist dies noch die harmlosere Variante, da sofort offenbar wird, dass hier irgendwo ein Fehler vorliegt. Schlechter wäre es, wenn statt dem Bezeichner der Konstante der Name der Objekteigenschaft falsch geschrieben worden wäre.

                // Suppose the property name had been misspelled.
                
                object.aLongAndDescriptiveIdentifier; // undefined
                

                In diesem Fall wird natürlich kein Fehler geworfen. Es wird einfach eine Eigenschaft unter dem falschen Namen angelegt. Es wird auch kein Fehler geworfen, wenn mit dem eigentlich richtigen Namen versucht wird, die Eigenschaft zu referenzieren.

                Wenn es keine solche Eigenschaft gibt, dann wird einfach undefined zurückgegeben.

                Die Wiederholung von Bezeichnern bei der Eigenschaftsdefinition kostet mehr Zeit und erhöht darüber hinaus das Risiko, dass man sich verschreibt und damit Fehler in das Programm einbaut, die gegebenenfalls erst sehr viel später auffallen.

                Auch das Lesen des Codes, etwa bei einer Code-Review, ist mit mehr kognitivem Aufwand verbunden, da immer geprüft werden muss, ob der Bezeichner auf beiden Seiten der Eigenschaftsdefinition richtig geschrieben ist.

                // Example using shorthand syntax
                
                const aLongAndDescriptiveIdentifier = 'value';
                
                
                // Just reference constant
                
                const object = { aLongAndDescriptiveIdentifier };
                

                Wird wie in dem Beispiel oben die Kurzschreibweise verwendet, dann muss nur noch ein Bezeichner auf Korrektheit geprüft werden.

                Insbesondere ist von Vorteil, dass wenn man sich bei dieser Notation verschreibt (abgesehen von dem unwahrscheinlichen Fall, dass innerhalb der lexikalischen Umgebung des Ausdrucks eine Bindung für den falsch geschriebenen Namen existiert), in jedem Fall ein Fehler produziert wird. Kann die Referenz nämlich nicht aufgelöst werden, dann führt dies unmittelbar zu einem ReferenceError.

                Ein Fehler wie oben, der verschleppt und erst zu einem späteren Zeitpunkt erkannt wird, kann hier gar nicht erst passieren.

                // First declare some constants
                
                const a = 1, b = 2, c = 3;
                
                
                // Then initialize object with properties
                
                const object = { a, b, c };
                

                Aus diesen Gründen würde ich empfehlen, in Fällen in denen für Variablen, Konstanten oder Parameter gleichnamige Objekteigenschaften definiert werden sollen, prinzipiell die Kurzschreibweise zu verwenden.

                Viele Grüße,

                Orlok

                1. Es wird auch kein Fehler geworfen, wenn mit dem eigentlich richtigen Namen versucht wird, die Eigenschaft zu referenzieren.

                  Also genau genommen mit dem falschen.

                  Wenn es keine solche Eigenschaft gibt, dann wird einfach undefined zurückgegeben.

                  Das ist nichts anderes als ein weiterer Designfehler von Javascript. Wenn ich lesend auf etwas zugreife, was es aber nicht gibt, sollte wenigstens eine Warnung kommen.

                  Aus diesen Gründen würde ich empfehlen, in Fällen in denen für Variablen, Konstanten oder Parameter gleichnamige Objekteigenschaften definiert werden sollen, prinzipiell die Kurzschreibweise zu verwenden.

                  Hm.

                  Du begründest also die Nutzung eines schlecht lesbaren Codes mit einem sauber konserviertem Designfehler der Programmiersprache.

                  Na gut. Insofern erscheint die Kurzschreibweise zumindest einen praktischen Grund zu haben. Immerhin ist es unwahrscheinlich dass man selbst Einfluss auf diejenigen hat, die Javascript entwickeln und auch mit den Browserherstellern sieht es ähnlich aus. Man muss mit dem Mist halt leben.

                  1. hi

                    Das ist nichts anderes als ein weiterer Designfehler von Javascript. Wenn ich lesend auf etwas zugreife, was es aber nicht gibt, sollte wenigstens eine Warnung kommen.

                    Sehe ich auch so. Und was soll ich sagen, in Perl isses auch so und das ist auch gut so, daß es beim Zugriff auf nicht definierte Dinge eben knallt. Nicht umsonst ist der Pseudohash ganz schnell wieder verschrottet worden.

                    MfG

                    1. hallo

                      hi

                      Das ist nichts anderes als ein weiterer Designfehler von Javascript. Wenn ich lesend auf etwas zugreife, was es aber nicht gibt, sollte wenigstens eine Warnung kommen.

                      Sehe ich auch so. Und was soll ich sagen, in Perl isses auch so und das ist auch gut so, daß es beim Zugriff auf nicht definierte Dinge eben knallt. Nicht umsonst ist der Pseudohash ganz schnell wieder verschrottet worden.

                      Ach in Perl bekommst du ein laues Lüftchen von einer Warning.

                      1. hallo

                        Ach in Perl bekommst du ein laues Lüftchen von einer Warning.

                        kein Problem aus einem lauen Lüftchen einen heißen Wüstensturm zu machen:

                        $SIG{__WARN__} = sub { die @_ };
                        

                        und siehe da werden Fehler wieder so wahrgenommen wie sie es verdient gehabt haben: Nämlich gleich beim Entwickeln.

                        MfG

                  2. Das ist nichts anderes als ein weiterer Designfehler von Javascript. Wenn ich lesend auf etwas zugreife, was es aber nicht gibt, sollte wenigstens eine Warnung kommen.

                    Ach komm :) Ich würde sagen, Javascript funktioniert einfach nur nicht so, wie du es gerne hättest.

                    Du greifst in diesem Fall nicht auf einen Speicherbereich zu der nicht existent ist, sondern auf Prototypen, welche zwischen Objektbäumen vererbt werden.

                    Was ich damit sagen will: andere Sprache, andere Konzepte. Du kannst nicht Regeln, oder Best Practices von C, Rust, Go ... auf Javascript anwenden. Oder gehörst du etwa auch zu denjenigen, die sich über die furchtbare Implementierung von Namespaces in CSS echauffieren? :)

                    Du bekommst deinen Referenz-Error, wenn du eine Variable in einem Scope definierst und nicht eine Objekteigenschaft.

                    Hier ein "schönes" Beispiel:

                    // alert(foo); // undefined
                    // alert(baz); // reference error: baz is not defined
                    // alert(window.bar) // undefined
                    // alert(bar); // reference error: bar is not defined
                    
                    bar = 100;
                    var foo = 200;
                    let baz = 300;
                    
                    // alert(foo); // 100
                    // alert(bar); // 200
                    // alert(window.bar) // 200
                    

                    Und hier eine genaue Erklärung. Keine Rechtfertigung.

                    Meine Erklärung sieht so aus: Wenn du auf eine Eigenschaft eines Objekt zugreifst durchläuftst du die ganze Prototypen-Kette durch. Wenn keine Eigenschaft gefunden wird erhälst du 'undefined'. Nicht definiert, da die Eigenschaft nicht definiert ist. Du greifst nicht auf einen undefinierten Speicherbereich zu, deshalb auch kein Referenz-Error. Mehr dazu.

                    Wenn du hingegen auf eine Variable in einem Scope zugreifst, greifst du effektiv auf einen Speicherbereich zu. Deshalb gibt es auch einen Referenz-Error.

                    Einen Vorteil, den ich darin sehe ist, dass ich lange Eigenschaftsketten bequem validieren kann, ohne jedes einzelne Glied auf Existenz checken zu müssen, bevor ich beispielsweise den Typ abfrage.

                    Ein weiterer Vorteil ist, dass ich Scripts in mehrere Dateien aufteilen kann mit folgendem sog. Module-Pattern, ohne mir über die Lade-Reihenfolge Gedanken machen zu müssen:

                    var module = (function (def) {
                      // code
                    	return def;
                    }(module || {}));
                    

                    Das würde einen Referenz-Error werfen, da ich module an die Funktion übergebe, bevor ich module definiere. Das ist übrigens nicht irgend ein Pattern, sondern ein grundlegende Vorgehensweise zur Strukturierung von Code in ECMAScript 2015.

                    lg

                    mark

                  3. Tach!

                    Wenn es keine solche Eigenschaft gibt, dann wird einfach undefined zurückgegeben.

                    Das ist nichts anderes als ein weiterer Designfehler von Javascript. Wenn ich lesend auf etwas zugreife, was es aber nicht gibt, sollte wenigstens eine Warnung kommen.

                    Wie löst du dann das Problem der Feature-Erkennung in unterschiedlichen Implementierungen? Versetz dich dazu in die Anfangszeit als es try-catch noch nicht gab. Auch damals musste man schon Programme schreiben können, die nicht gleich mit Fehler aussteigen, nur weil der eine Browser eine bestimmte Objekteigenschaft nicht kennt, die in anderen Browsern existiert. Wie testest du das, ohne dass dabei gleich die Konsole vollgemüllt wird oder das Script stirbt?

                    Eine Lösung wäre vielleicht à la PHPs Sprachkonstrukt isset(). Das greift nicht wirklich zu, sondern prüft die Existenz und wirft dabei auch keinen Fehler. Aber was genau wäre dabei der Unterschied zwischen

                    if (isset(foo.bar))
                    

                    und

                    if (foo.bar != undefined)
                    

                    Javascript hat Möglichkeiten, die Nichtexistenz zu erkennen. Wenn der Programmierer sie nicht nutzt und lieber auf eine Warnung wartet, wenn er ungeprüft auf unbekannte Daten zugreift, sehe ich das nicht als das Problem von Javascript an.

                    Und es ist ja nicht so, dass gar nichts kommt. Beim weiteren Zugreifen hat man dann auch einen schönen Fehler:

                    var foo = {};
                    console.log(foo.bar); // nur undefined
                    console.log(foo.bar.qux); // Fehler, weil ein undefined keine Eigenschaften hat.
                    

                    dedlfix.

                    1. Hallo dedlfix,

                      Eine Lösung wäre vielleicht à la PHPs Sprachkonstrukt isset(). Das greift nicht wirklich zu, sondern prüft die Existenz und wirft dabei auch keinen Fehler. Aber was genau wäre dabei der Unterschied zwischen

                      if (isset(foo.bar))
                      

                      und

                      if (foo.bar != undefined)
                      

                      In JS würde man als isset-Äquivalent allerdings eher hasOwnProperty benutzen:

                      if(foo.hasOwnProperty('bar'))
                      

                      Denn:

                      const foo = { bar: undefined };
                      console.log(foo.bar !== undefined);
                      console.log(foo.hasOwnProperty('bar'));
                      delete foo.bar;
                      console.log(foo.hasOwnProperty('bar'));
                      

                      LG,
                      CK

                      1. Tach!

                        Eine Lösung wäre vielleicht à la PHPs Sprachkonstrukt isset(). Das greift nicht wirklich zu, sondern prüft die Existenz und wirft dabei auch keinen Fehler. Aber was genau wäre dabei der Unterschied zwischen

                        if (isset(foo.bar))
                        

                        und

                        if (foo.bar != undefined)
                        

                        In JS würde man als isset-Äquivalent allerdings eher hasOwnProperty benutzen:

                        if(foo.hasOwnProperty('bar'))
                        

                        Ja, das ist auch eine Möglichkeit, solange man mit den direkten Eigenschaften zufrieden ist, was wohl meist der Fall ist.

                        Denn:

                        const foo = { bar: undefined };
                        console.log(foo.bar !== undefined);
                        console.log(foo.hasOwnProperty('bar'));
                        delete foo.bar;
                        console.log(foo.hasOwnProperty('bar'));
                        

                        Das ist eine zu beachtende Besonderheit. Aber der Unterschied zwischen einem undefined bei einer nicht vorhandenen Eigenschaft und einem undefined als Wert in einer vorhandenen Eigenschaft ist praktisch nicht vorhanden. Man will ja im Allgemeinen mit dem Wert arbeiten und nicht mit dem Fakt der Existenz einer Eigenschaft. Insofern würde ich eher auf undefined (oder meist falsy) prüfen statt mit hasOwnProperty(), weil mir ein true bei einem folgenden Lesevorgang auf den Wert undefined auch nicht weiter hilft.

                        Übrigens, wenn der Wert einer Eigenschaft in PHP null ist, liefert isset() auch false.

                        dedlfix.

                        1. Hallo dedlfix,

                          Ja, das ist auch eine Möglichkeit, solange man mit den direkten Eigenschaften zufrieden ist, was wohl meist der Fall ist.

                          Naja, wenn nicht gibt es in.

                          Das ist eine zu beachtende Besonderheit. Aber der Unterschied zwischen einem undefined bei einer nicht vorhandenen Eigenschaft und einem undefined als Wert in einer vorhandenen Eigenschaft ist praktisch nicht vorhanden.

                          Das sehe ich anders. Ich habe den Unterschied schon öfter gebraucht, und gerade in einem Forum, dass Web-Technologien vermittelt, sollte das nicht so unter den Teppich gekehrt werden.

                          LG,
                          CK

                          1. Tach!

                            Das ist eine zu beachtende Besonderheit. Aber der Unterschied zwischen einem undefined bei einer nicht vorhandenen Eigenschaft und einem undefined als Wert in einer vorhandenen Eigenschaft ist praktisch nicht vorhanden.

                            Das sehe ich anders. Ich habe den Unterschied schon öfter gebraucht, und gerade in einem Forum, dass Web-Technologien vermittelt, sollte das nicht so unter den Teppich gekehrt werden.

                            Ja, es gibt auch Fälle, da sind die Keys für eine bestimmte Funktionalität wichtig. Diese Fälle "darf" man natürlich auch berücksichtigen. Wenn aber der Key lediglich ein Name für einen Wert ist, dann interesiert mich der Wert und nicht, ob der Name existiert. Da reicht ein

                            if (foo && foo.bar && foo.bar.qux)
                            

                            völlig aus, um zu testen, ob foo.bar (als Objekt) existiert und in foo.bar.qux was sinnvolles drinsteht - unter der Voraussetzung, dass nur truthy Werte für den gegebenen Fall als sinnvoll angesehen werden. Ich würde in einem solchen Fall nicht mit hasOwnProperty() und dem zusätzlich notwendigen Test, dass der Wert weder undefined noch null ist, arbeiten, wenn die obige Syntax ausreichend ist.

                            dedlfix.

                            1. Hallo dedlfix,

                              if (foo && foo.bar && foo.bar.qux)
                              

                              völlig aus, um zu testen, ob foo.bar (als Objekt) existiert und in foo.bar.qux was sinnvolles drinsteht

                              Für sowas würde ich immer einen Helper schreiben, der mir den ganzen Boilerplate abnimmt, z.B. sowas:

                              function getPath(obj, key, dfault = undefined) {
                                const path = key.split(/\./);
                                let i = 0;
                              
                                while (obj && i < path.length) {
                                  obj = obj[path[i++]];
                                }
                              
                                return obj === undefined ? dfault : obj;
                              }
                              
                              console.log(getPath({}, "a.0.c"));
                              console.log(getPath({ a: [{ c: 'd' }]}, "a.0.c"));
                              console.log(getPath({}, "a.0.c", 'd'));
                              

                              LG,
                              CK

                              1. Tach!

                                if (foo && foo.bar && foo.bar.qux)
                                

                                völlig aus, um zu testen, ob foo.bar (als Objekt) existiert und in foo.bar.qux was sinnvolles drinsteht

                                Für sowas würde ich immer einen Helper schreiben, der mir den ganzen Boilerplate abnimmt, z.B. sowas:

                                console.log(getPath({}, "a.0.c"));
                                console.log(getPath({ a: [{ c: 'd' }]}, "a.0.c"));
                                console.log(getPath({}, "a.0.c", 'd'));
                                

                                Das würde ich nicht machen, weil man hier mit Magic Strings arbeiten muss. Wenn sich an den Bezeichnern etwas ändert, muss man diese Strings mit berücksichtigen.

                                Dafür bieten zwar einige IDEs Find-Hilfen an ("suche den Namen auch in Strings"), aber das ist nicht das Gelbe vom Ei, verglichen mit "ersetz mir alles" - besonders wenn man mit TypeScript eine schöne Typisierung zur Verfügung hat.

                                dedlfix.

                                1. Hallo dedlfix,

                                  Das würde ich nicht machen, weil man hier mit Magic Strings arbeiten muss. Wenn sich an den Bezeichnern etwas ändert, muss man diese Strings mit berücksichtigen.

                                  Ja, muss ich halt auch bei properties.

                                  Dafür bieten zwar einige IDEs Find-Hilfen an ("suche den Namen auch in Strings"), aber das ist nicht das Gelbe vom Ei, verglichen mit "ersetz mir alles" - besonders wenn man mit TypeScript eine schöne Typisierung zur Verfügung hat.

                                  Ja, bei Typescript bietet der Zugriff über Properties tatsächlich Vorteile. Leider kann ich kein TypeScript benutzen 😟

                                  LG,
                                  CK

                                  1. Das würde ich nicht machen, weil man hier mit Magic Strings arbeiten muss. Wenn sich an den Bezeichnern etwas ändert, muss man diese Strings mit berücksichtigen.

                                    Ja, muss ich halt auch bei properties.

                                    Vorschlag zur Güte:

                                    function lense (target) {
                                      const wrap = () => target;
                                      return new Proxy(wrap, {
                                        get : function (_, property) {
                                          return lense(target instanceof Object ? target[property] : undefined)
                                        },
                                        apply : function() {
                                          return target
                                        }
                                      });
                                    }
                                    
                                    lense({foo:{bar:42}}).foo.bar() // 42
                                    lense({foo:{bar:42}}).bar.foo() // undefined
                                    

                                    Ist aber derbes Meta-Programming-Gehacksel, vielleicht doch besser nicht so machen.

                                    1. Habs gerade mal getestet, klappt auch gar nicht. Aber irgendwie so in der Art würde es mit Proxies wohl auch gehen.

                                      Edit: Hab das Beispiel korrigiert, funktioniert nun.

                                2. Hallo dedlfix,

                                  wenn ich für sowas einen Helper bauen wollte, dann sähe das so aus:

                                  let x = { y: { t: { q:7 } } };
                                  
                                  console.log(chainGuard(() => x.y.t.q));   // 7
                                  console.log(chainGuard(() => x.z.t.q));   // undefined
                                  
                                  function chainGuard(func) {
                                     try { return func(); } catch { return undefined; }
                                  }
                                  

                                  Der Aufbau eines try-catch Rahmens dürfte weniger zeitraubend sein als das Parsen von magic strings oder das abklappern einer Function-Liste, die sich Schritt für Schritt durch die Kette arbeitet.

                                  Rolf

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

                                    wenn ich für sowas einen Helper bauen wollte, dann sähe das so aus:

                                    […]

                                    Auch eine nette Idee.

                                    Der Aufbau eines try-catch Rahmens dürfte weniger zeitraubend sein als das Parsen von magic strings oder das abklappern einer Function-Liste, die sich Schritt für Schritt durch die Kette arbeitet.

                                    Performance ist counter-intuitive. Ohne Benchmarks sind das reine Mutmaßungen 😀

                                    LG,
                                    CK

                                  2. Tach!

                                    wenn ich für sowas einen Helper bauen wollte, dann sähe das so aus:

                                    let x = { y: { t: { q:7 } } };
                                    
                                    console.log(chainGuard(() => x.y.t.q));   // 7
                                    console.log(chainGuard(() => x.z.t.q));   // undefined
                                    
                                    function chainGuard(func) {
                                       try { return func(); } catch { return undefined; }
                                    }
                                    

                                    Die Idee finde ich gut. Aber was spräche denn dagegen, das try-catch gleich im Code unterzubringen und den Rest so zuschreiben, als ob alles ok wäre? Offensichtlich gibts im fiktiven Anwendungsfall die Möglichkeit, dass unvollständige Objekte ankommen, und man möchte darauf reagieren. Das ist doch im Prinzip nichts anderes als das Abfangen eines Fehlers, oder?

                                    dedlfix.

                                    1. Hallo dedlfix,

                                      Aber was spräche denn dagegen, das try-catch gleich im Code unterzubringen und den Rest so zuschreiben, als ob alles ok wäre?

                                      Boilerplate. Weniger Code ist mehr gut. Wenn ich etwas regelmäßig wieder auftretendes in einer Funktion kapseln kann, dann sollte ich das tun. Jede nicht geschriebene Zeile Code kann auch keinen Fehler enthalten.

                                      LG,
                                      CK

                                      1. Tach!

                                        Aber was spräche denn dagegen, das try-catch gleich im Code unterzubringen und den Rest so zuschreiben, als ob alles ok wäre?

                                        Boilerplate. Weniger Code ist mehr gut. Wenn ich etwas regelmäßig wieder auftretendes in einer Funktion kapseln kann, dann sollte ich das tun. Jede nicht geschriebene Zeile Code kann auch keinen Fehler enthalten.

                                        Das verstehe ich nicht. Es wird statt if-else mit Funktionsaufruf lediglich ein try-catch notiert. Der Rest bleibt gleich.

                                        if (test(foo.bar.qux)) {
                                          machWasMit(foo.bar.qux);
                                        } else {
                                          fehlerbehandlung();
                                        }
                                        

                                        vs.

                                        try {
                                          machWasMit(foo.bar.qux);
                                        } catch {
                                          fehlerbehandlung();
                                        }
                                        

                                        dedlfix.

                                        1. Hallo dedlfix,

                                          Das verstehe ich nicht. Es wird statt if-else mit Funktionsaufruf lediglich ein try-catch notiert. Der Rest bleibt gleich.

                                          if (test(foo.bar.qux)) {
                                            machWasMit(foo.bar.qux);
                                          } else {
                                            fehlerbehandlung();
                                          }
                                          

                                          vs.

                                          try {
                                            machWasMit(foo.bar.qux);
                                          } catch {
                                            fehlerbehandlung();
                                          }
                                          

                                          Das Beispiel (und auch das von Rolf) ist verkürzt, meine Version hatte nicht umsonst einen Parameter für den Default-Wert mit drin 😀 erst damit wird es wirklich praktisch.

                                          LG,
                                          CK

                                    2. Hallo dedlfix,

                                      unvollständige Objekte (...) und man möchte darauf reagieren

                                      Wenn Du reagieren willst, dann reicht kein try-catch. Dann hast Du aber ein ganz anderes Thema, denn die Reaktionen können mannigfaltig sein.

                                      Wenn's nur ein Default-Wert ist, da verweise ich dann auf CK.

                                      Rolf

                                      --
                                      sumpsi - posui - clusi
                              2. Tach!

                                if (foo && foo.bar && foo.bar.qux)
                                

                                Für sowas würde ich immer einen Helper schreiben, der mir den ganzen Boilerplate abnimmt, z.B. sowas:

                                function getPath(obj, key, dfault = undefined) {
                                  const path = key.split(/\./);
                                  let i = 0;
                                
                                  while (obj && i < path.length) {
                                    obj = obj[path[i++]];
                                  }
                                
                                  return obj === undefined ? dfault : obj;
                                }
                                
                                console.log(getPath({}, "a.0.c"));
                                console.log(getPath({ a: [{ c: 'd' }]}, "a.0.c"));
                                console.log(getPath({}, "a.0.c", 'd'));
                                

                                Was mir beim Nachdenken auch noch aufgefallen ist, du machst mit der Funktion nichts anderes als in meinem Beispiel, nur umständlicher. Die obige Prüfung ist gängige Praxis und kommt ohne eine Hilfsfunktion aus, die man erst verstehen muss. Die Zwischenteile des Pfades prüfst du ebenfalls nur falsy - was ja auch völlig ausreichend ist. Lediglich den letzten Teil prüfst du auf exakt undefined, wobei auch hier keine Rolle spielt, ob die Eigenschaft gar nicht oder mit dem Wert undefined vorhanden ist. Ich seh da jetzt noch nicht den Sinn in dieser Hilfsfunktion.

                                Es wird ein wenig besser je länger der Pfad zur Eigenschaft wird. Aber dann würde ich auch eher versuchen, den Code besser aufzuteilen, so dass sich nicht die Notwendigkeit einer solchen Rattenschwanzprüfung ergibt. Vermutlich gibt es auch noch weiter vorn im Pfad etwas zu prüfen, so dass bei der Gelegenheit gleich eine Variable mit Referenz auf das Restobjekt angelegt werden kann. Dann hat man bei dessen Prüfung weniger Glieder zu durchlaufen.

                                dedlfix.

                                1. Hallo dedlfix,

                                  Was mir beim Nachdenken auch noch aufgefallen ist, du machst mit der Funktion nichts anderes als in meinem Beispiel, nur umständlicher.

                                  Nein, nur allgemeiner. Damit beliebige Tiefen möglich werden.

                                  Die obige Prüfung ist gängige Praxis

                                  Helper, die Zugriffspfade in Objekten prüfen sind auch gängige Praxis 😉

                                  Ich seh da jetzt noch nicht den Sinn in dieser Hilfsfunktion.

                                  Sie ersparen Boilerplate und sichern ab, dass man die Prüfung, ob der Pfad vollständig zugreifbar ist, nicht vergisst. Statt if(foo && foo.bar && foo.bar[0] && foo.bar[0].baz) reicht ein if(getPath(foo, 'bar.0.baz')), oder sogar ein getPath(foo, 'bar.0.baz', '(unbekannt)').

                                  Es wird ein wenig besser je länger der Pfad zur Eigenschaft wird. Aber dann würde ich auch eher versuchen, den Code besser aufzuteilen, so dass sich nicht die Notwendigkeit einer solchen Rattenschwanzprüfung ergibt.

                                  Je mehr ich mit APIs spreche, desto mehr zeigt sich, dass diese Funktion (und ihr Counterpart putPath()) einfach praktisch ist. Weniger Boilerplate gleich mehr gut.

                                  Vermutlich gibt es auch noch weiter vorn im Pfad etwas zu prüfen, so dass bei der Gelegenheit gleich eine Variable mit Referenz auf das Restobjekt angelegt werden kann. Dann hat man bei dessen Prüfung weniger Glieder zu durchlaufen.

                                  Naja, dann macht man das mit getPath auch:

                                  const part = getPath(foo, "bar.0", {});
                                  if(part.a && part.b) {
                                    // ...
                                  }
                                  

                                  LG,
                                  CK

                      2. Hallo Ingrid,

                        in dem Zusammenhang:

                        LG,
                        CK

                        1. Tach!

                          Genau, praktisch dasselbe.

                          dedlfix.

                          1. So einfach ist das nicht immer. Man könnte ja mal eine numerische 0 einführen die im boolschen Kontext einen wahren Wert ergibt, aber in JS tut man lieber nur alten Schrott neu verpacken wie z.B. FormData oder pseudo Hashes.

                            MfG

                          2. Tach!

                            Genau, praktisch dasselbe.

                            Kommt wohl drauf an für wen und welcher Situation:

                            Es ist nicht "praktisch dasselbe" wenn man versucht, den Status der Klopapierrolle abzufragen und, wenn leer, eine neue Rolle ins DF1STPR ("depository for one small toilet paper roll") einzuhängen.

                            1. Tach!

                              Genau, praktisch dasselbe.

                              Kommt wohl drauf an für wen und welcher Situation:

                              Ja klar. Wenn man ein Geschäft machen möchte, muss man wissen, ob man eine Rolle oder sie inklusive Halterung verkaufen kann. Wenn man ein Geschäft machen muss, sind die unterschiedlichen Zustände des Nichtvorhandenseins von Papier und Halterung unerheblich.

                              dedlfix.

                        2. Hallo Christian,

                          das linke Bild ist bekanntlich nicht 0, sondern 404 - page not found

                          Rolf

                          --
                          sumpsi - posui - clusi
                  4. Wenn es keine solche Eigenschaft gibt, dann wird einfach undefined zurückgegeben.

                    Das ist nichts anderes als ein weiterer Designfehler von Javascript. Wenn ich lesend auf etwas zugreife, was es aber nicht gibt, sollte wenigstens eine Warnung kommen.

                    Nein, das Verhalten ist statisch analysierbar, wenn du deinen Editor richtig eingestellt hast, bekommst du das schon beim Tippen angezeigt.

                    Warnhinweis von VSCode falls Objekteigenschaft nicht vorhanden

                2. Außerdem ergeben Destrukturierung und Konstruktion mit der Kurzschreibweise eine hübsche Symmetrie, da freut sich der kleine Monk in mir.

                  // Konstruktion
                  const user = {name, birthday, id}
                  // Destrukturierung
                  const {name, birthday, id} = user
                  
        2. i.m.h.o. "syntaktisch korrekt". Ich würde den Verwender verbal verprügeln weil so was "nicht lesbar" ist.

          Beziehst du dich auf den ersten Teil oder den zweiten?

          var ich_bin_ein_Objekt_Index = /*ich bin Objekt-value*/ Math.max(1, 2, 3);
          Objekt_in_Array.push({ich_bin_ein_Objekt_Index});
          

          Die zweite Zeile.

          1. In Perl ist diese Totgeburt als Pseudohash bekanntgeworden. Ich bin mal gespannt wo die noch wieder auftaucht.

            .

            1. Auch wenn eines Deiner Worte hart klingt: Ich hätte jetzt nicht gedacht, dass jemand dieses, aus meiner Sicht krass misslungene Syntaxkonstrukt auch nur mit einem Klick verteidigt.

              Offenbar mussten diejenigen, die es in JS einbauten, sich nicht mit etlichen solcher Fehler herumärgern, die ihre Ursache darin haben, dass z.B. das sehr früh konstruierte Perl sich an die noch früher (vor rund 50 Jahren!) konstruierte Unix-Shell anlehnte. Und die entstand also, als Speicher sehr knapp war und man sich über die Lesbarkeit von Programmen bzw. Skripten nur sekundär Gedanken gemacht hat.

              Inzwischen da wohl jemand so modern geworden, dass er den früheren Ärger vergessen hat und nur auf die kurze Notation schielt.

              Zum Glück muss man nicht alles machen, was geht.

              1. Danke !!!

    2. Entschuldigung, da war die Fragestellung ein wenig unpräzise.

      Es ging mir im Endeffekt genau darum, wie eine Variable in ein Objekt sozusagen "transkribiert" wird, also um Teil 1 deiner Antwort.

      Danke für die Aufklärung!