MB: Function Borrowing mit Konstruktor-Funktion?

moin,

ich möchte zu meinem Verständnis Function Borrowing auf Prototype-Inheritance wie folgt anwenden (ich habe den Code gekürzt damit mein Verständnis-Problem besser verdeutlicht wird)

// Parent Class
function AbstractUser() {
  // Code
}

// Child Class
function User( user ) {
  AbstractUser.call( this );
  this.personals = {
    first: user.first,
    first: user.last
  }
}

// Function Borrower
function Borrower(){}

// Lend Function
Borrower.prototype.getFormalName = function() {
  return `${this.personals.last}, ${this.personals.first}`
}

let mm = new User( { first: 'Max', last: 'Mustermann' } );
let b = new Borrower();

// Function Borrowing
b.getFormalName.apply( mm ); // "Mustermann, Max"
mm.getFormalName(); // TypeError: mm.getFormalName is not a function

eigentlich sollte die Funktion getFormalName von Borrower welches mit b erzeugt wurde, diese Funktion über die BuiltIn-Funktion apply mit dem Argument mm bereit stellen.

  • Was lief schief bei mir im Code?
  • Klappt Function-Borrowing nur mit Object Literals? Denn da funktioniert es!
  • Müssen zum Funktionsborgen beide Objekte in der Struktur exakt gleich sein mit ausnahme der Funktion die geborgt wird?

Edit Rolf B: Hinweis von MB bezüglich DummyUser = Borrower eingepflegt

lgmb

--
Sprachstörung
  1. Hallo MB,

    Du definierst getFormalName auf dem Prototypobjekt von DummyUser.

    Wie der Borrower da herankommt, ist aus deinem Posting nicht ersichtlich - das ist Magie.

    Der User mm kommt jedenfalls nicht dran. Um das zu können, müsste DummyUser eine Superklasse von User sein. Die Klassenhierarchie in Bezug auf DummyUser ist aber nicht ersichtlich.

    Was lief schief bei mir im Code?

    Keine Ahnung. Dazu war deine Kürzung zu radikal. Oder es ist zu viel Spagetti im Objektmodell.

    Rolf

    --
    sumpsi - posui - obstruxi
    1. moin,

      Du definierst getFormalName auf dem Prototypobjekt von DummyUser.

      Oh, soll...

      Borrower.prototype.getFormalName = function() {
        return `${this.personals.last}, ${this.personals.first}`
      }
      

      ...sein. Ich hab's zur Verdeutlichung im Forum von DummyUser zu Borrower geändert und habe leider was übersehen, entschuldige. Sonst müsste mein veranschaulichte Problem stimmen.

      lgmb

      --
      Sprachstörung
      1. Hallo MB,

        Es bleibt aber die Frage, wie der DummyUser oder Borrower in der Klassenhierarchie zu User/AbstractUser in Beziehung steht.

        Ohne diese Beziehung kann der User getFormalName nicht kennen.

        Ich verstehe auch überhaupt nicht, was Du mit deiner Borgerei bezwecken willst.

        Wenn Du eine Klasse X mit der Methode foo hast und diese Methode "borgen" willst, um sie auf ein Objekt der Klasse Y anzuwenden, dann macht man das normalerweise so:

        y = new Y();
        
        X.prototype.foo.apply(y)
        

        Das funktioniert natürlich nur, wenn y halbwegs "x-artig" ist, so dass die foo-Methode ihr erwartetes Umfeld vorfindet.

        Was man auch machen kann, ist eine Funktion an zwei Prototypen zuweisen (bzw. aus dem einen Prototypen herausholen und im anderen speichern). Sowas habe ich gerne als trivialen Polyfill für die NodeList gemacht, um dort im Internet Explorer eine forEach Methode bereitzustellen:

        if (!NodeList.prototype.forEach)
        {
           NodeList.prototype.forEach = Array.prototype.forEach;
        }
        

        Rolf

        --
        sumpsi - posui - obstruxi
        1. moin,

          Es bleibt aber die Frage, wie der DummyUser oder Borrower in der Klassenhierarchie zu User/AbstractUser in Beziehung steht. […]

          Ich habs jetzt. Du hast mir klarheit verschaffen können. Danke :). Sry für das Missverständnis :/.

          function getFormalName() {
            return `${this.personal.last}, ${this.personal.first}`
          }
          
          let mm = new User( {/*max musterman*/} );
          
          getFormalName.bind( mm )(); // "Mustermann, Max"
          

          obriges war mein Ziel.

          Das funktioniert natürlich nur, wenn y halbwegs "x-artig" ist, so dass die foo-Methode ihr erwartetes Umfeld vorfindet.

          Ok verstanden Danke.

          Was man auch machen kann, ist eine Funktion an zwei Prototypen zuweisen […]

          Interessant :)

          lgmb

          --
          Sprachstörung
          1. Hallo MB,

            sicher, dass Du das wolltest?

            Mit bind erzeugst Du eine neue Funktion, die getFormalName an mm bindet. D.h. du schaffst damit eine Assoziation zwischen einer Funktion und einem Objekt. Und diese neue Funktion musst Du speichern, sonst ist sie gleich wieder weg.

            Es ist nicht so sinnvoll, getFormalName.bind(mm)() zu schreiben. Das erzeugt den Overhead des Bindings und schmeißt das Gebinde gleich wieder weg. Für eine Einmalaktion ist getFormalName.apply(mm) viel sinnvoller.

            bind lohnt sich nur, wenn Du das Gebinde behalten willst. Aber - wie gesagt - dann muss es gespeichert werden.

            let mmFormalName = getFormalName.bind(mm);
            console.log(mmFormalName());   // -> Mustermann, Max
            

            Das sieht dann allerdings auch nicht mehr objektorientiert aus. Für eine objektorientierte Schreibweise, wenn also mm.getFormalName() funktionieren soll (ohne User.prototype anzugreifen), müsstest Du dies tun:

            mm.getFormalName = getFormalName;
            mm.getFormalName();            // -> Mustermann, Max
            

            Damit erzeugst Du am mm Objekt - also einer Instanz eines User-Objekts, eine Eigenschaft getFormalName, in der ein Verweis auf die getFormalName-Funktion gespeichert ist.

            Wenn Du die getFormalName Funktion als Methode für alle User-Objekte bereitstellen willst, musst Du sie an User.prototype.getFormalName zuweisen - aber das wolltest Du ja offenbar nicht

            Fazit:

            Es gibt 4 Stufen, wie Du getFormalName mit User verbinden kannst.

            • Nur für einen Call: getFormalName.apply (oder getFormalName.call)
            • Permanent für eine Instanz des Objekts, als Funktion: mit .bind
            • Permanent für eine Instanz, am Objekt gespeichert: Als Eigenschaft am Objekt
            • Permanent für alle Instanzen von User: Als Eigenschaft an User.prototype.

            Rolf

            --
            sumpsi - posui - obstruxi
            1. moin,

              sicher, dass Du das wolltest?

              Danke Dir für die sehr gute Erläuterung.

              Ja ich bin mir sicher. Alldies was du aufzeigst hatte ich schon im Kopf. Es geht mir um das gelernte anwenden zu können, auch wenn der Code nicht sooo sinnvoll ist. Es geht um den Lerneffekt. Guten Morgen.

              lgmb

              --
              Sprachstörung
  2. @@MB

    // Child Class
    function User( user ) {
      AbstractUser.call( this );
      this.personals = {
        first: user.first,
        first: user.last
      }
    }
    

    Das sollte

      this.personals = {
        first: user.first,
        last: user.last
      }
    

    sein, nicht wahr?

    Es geht aber nicht um den ersten oder letzten Nutzer. Ich würde die Eigenschaften firstName / lastName benennen. Oder noch besser givenName / familyName. ☞ Personennamen aus aller Welt

    🖖 Живіть довго і процвітайте

    --
    When the power of love overcomes the love of power the world will know peace.
    — Jimi Hendrix
    1. Hallo Gunnar,

      Oder noch besser givenName / familyName. ☞ Personennamen aus aller Welt

      das ist nicht unbedingt besser. Es würde zum Beispiel in Island nicht funktionieren. Da bekommen die Kleinen nur einen Vornamen; das, was für uns wie ein Nachname aussieht, ist in Wirklichkeit der Vorname des Vaters. Hat zum Beispiel der Sven einen Sohn und nennt ihn Gunnar, dann heißt der Knabe mit vollem Namen Gunnar Svensson, also etwa Gunnar, Sohn von Sven. Hat Gunnar dann zwei, drei Jahrzehnte später eine Tochter, die er Elin nennt, dann heißt das Mädel nach isländischem Namensschema Elin Gunnarsdottir, also Elin, Tochter von Gunnar.

      Deswegen sind Telefonverzeichnisse in Island auch nach Vornamen sortiert - alles andere wäre wenig sinnvoll.

      Einen schönen Tag noch
       Martin

      --
      Мир для України.
      1. @@Der Martin

        Hat Gunnar dann zwei, drei Jahrzehnte später eine Tochter, die er Elin nennt, dann heißt das Mädel nach isländischem Namensschema Elin Gunnarsdottir

        Gunnarsdóttir.

        Und ja, das steht auch in dem Artikel.

        Dennoch gibt der Artikel gute Gründe an, die gegen firstName / lastName sprechen.

        In Schema.org > Person heißt es auch givenName und familyName.

        🖖 Живіть довго і процвітайте

        --
        When the power of love overcomes the love of power the world will know peace.
        — Jimi Hendrix
        1. n'Abend,

          Hat Gunnar dann zwei, drei Jahrzehnte später eine Tochter, die er Elin nennt, dann heißt das Mädel nach isländischem Namensschema Elin Gunnarsdottir

          Gunnarsdóttir.

          oh ja, sorry, das ist mir durch die Lappen gegangen (und ich meine nicht den finnischen Volksstamm). Wobei ich nicht weiß, ob das für die Isländer nur ein Formfehler oder ein bedeutender Unterschied ist, oder was das in der Aussprache für einen Unterschied macht.

          Und ja, das steht auch in dem Artikel.

          Normalerweise folge ich deinen Links erstmal, weil sie meist mit Bedacht gewählt und durchaus informativ sind. Hätte das mal diesmal auch getan - dann wäre mein Post hyperliquid gewesen.

          In Schema.org > Person heißt es auch givenName und familyName.

          Was aber aus genannten Gründen in manchen Kulturen irreführend sein kann.

          Einen schönen Tag noch
           Martin

          --
          Мир для України.
    2. moin,

      Das sollte

        this.personals = {
          first: user.first,
          last: user.last
        }
      

      sein, nicht wahr?

      Ups ja du hast recht. Sry dafür 😕. Zurück zum Function-Borrowing Problem…

      P.S.: Ich bin mir sehr sicher, dass man dieses Codebeispiel sinnvoller, eleganter, besser und anders lösen kann, jedoch geht es mir hier um meinen Lerneffekt von Fuction-Borrowing.

      lgmb

      --
      Sprachstörung