Function Borrowing mit Konstruktor-Funktion?
MB
- javascript
- programmiertechnik
1 Rolf B0 Gunnar Bittersmann0 Der Martin0 MB
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.
Edit Rolf B: Hinweis von MB bezüglich DummyUser = Borrower eingepflegt
lgmb
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
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
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
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
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.
Rolf
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
@@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
🖖 Живіть довго і процвітайте
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
@@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
.
🖖 Живіть довго і процвітайте
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
undfamilyName
.
Was aber aus genannten Gründen in manchen Kulturen irreführend sein kann.
Einen schönen Tag noch
Martin
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