OOP in JS und prozedural
Florian Stascheck
- zur info
Hallo,
Ich hab mal folgendes Beispiel entwickelt, vielleicht hilft es ja einem von euch:
1: function a(string,param) {
2: this.string = string+'';
3: param = param || false;
4: if(!param) {
5: return new a(string,true);
6: }
7: }
8: var x = a('foo');
9: var y = new a('bar');
10: alert(x.string+y.string);
Es wird foobar ausgegeben. Der Sinn ist, dass eine Funktion, wenn sie prozedural aufgerufen wurde, eine Instanz von sich selbst zurückgibt. Das mit dem param ist so erprobt, dass es funktioniert. Gegebenfalls zwischen string und param weitere Parameter einfügen, in Zeile 5 muss man dann aber den Aufruf entsprechend abwandeln.
Mit der Hoffnung, dass es jemandem hilft, Flo
Mit der Hoffnung, dass es jemandem hilft, Flo
Es scheint du suchst die Eigenschaft constructor?
function b(string) {
if(this.constructor != b){
return new b(string);
}
this.string = new String(string);
}
var x = b('foo');
var y = new b('bar');
alert(x.string + y.string);
Struppi.
function b(string) {
if(this.constructor != b){
return new b(string);
}
if (this.constructor != arguments.callee) {
throw new Error("Es macht wirklich keinen Sinn, einen Konstruktor ohne new aufzurufen und der es auch noch zulässt. Man sollte solche Mehrdeutigkeiten durch klare Fehlermeldungen vermeiden, anstatt zu sie durch Fehlertoleranz zu unterstützen.");
}
Mathias
Hallo,
if (this.constructor != arguments.callee) {
throw new Error("Es macht wirklich keinen Sinn, einen Konstruktor ohne new aufzurufen und der es auch noch zulässt. Man sollte solche Mehrdeutigkeiten durch klare Fehlermeldungen vermeiden, anstatt zu sie durch Fehlertoleranz zu unterstützen.");
Für ein möglichst "liberales" Framework z.B. sollte diese Option mit einem console.debug("Bitte in Zukunft soundso aufrufen") aber trotzdem gegeben sein.
mfg, Flo
Für ein möglichst "liberales" Framework z.B. sollte diese Option mit einem console.debug("Bitte in Zukunft soundso aufrufen") aber trotzdem gegeben sein.
Solche Sachen macht man, wenn man einmal eine schlechte API definiert hat, dann merkt, dass sie schlecht war, und sie neu konzipiert, aber in der neuen Version noch abwärtskompatibel bleiben will. Dann erklärt man die API für »deprecated«, lässt sie auslaufen und entfernt sie irgendwann ganz.
Wenn man jedoch eine API von Grund auf neu definiert, definiert man keine solchen schlechten Kompromisse. Bzw. folgendes sollte man natürlich: Prüfen, ob die Methoden korrekt aufgerufen werden, und wenn nicht, dann hat es Fehler zu hageln! Mit allem anderen (z.B. Meldungen in der Konsole - die gar nicht jeder Browser hat, in die JavaScript-Autoren nicht reinschauen, sofern kein Fehler passiert) tut man dem Programmierer überhaupt keinen Gefallen, sondern sorgt nur dafür, dass der Fehler in sein Programm einbaut, die ihm früher oder später zum Verhängnis werden.
Ein Framework hat nicht liberal zu sein, sondern eine wohl definierte und eindeutige API zu implementieren. Die kann natürlich flexibel sein (z.B. Function Overloading), solange sie konsistent bleibt. Der Unterschied zwischen Funktionsaufruf und Konstruktoraufruf ist jedoch konzeptionell gesehen ein Unterschied ums Ganze - auch wenn es in JavaScript intern nur ein kleiner Unterschied ist (einmal wird die Funktion im Kontext eines frischen Objects, einmal im globalen Kontext ausgeführt). Wer den Unterschied nicht kennt oder ignoriert und mithilfe einer solchen »liberalen« API gänzlich einebnet, sollte m.M.n. keine objektorientierten Bibliotheken verwenden. Wenn OOP-Pattern letztlich optional sind, kann man sich die ganze Abstraktion auch sparen. Wieso sollte ich mir eine sinnhafte Objektmodellierung ausdenken und gleichzeitig eine Möglichkeit anbieten, das Konzept zu untergraben?
Mathias
Hallo,
Es scheint du suchst die Eigenschaft constructor?
Ich denke, schon :D
mfg, Flo
gruss Flo,
obwohl Du ja schon sanft vom himmel geholt wurdest, kriegst Du von mir
auch noch ein paar warme worte hinterhergereicht.
... Der Sinn ist, dass eine Funktion, wenn sie prozedural aufgerufen
wurde, eine Instanz von sich selbst zurückgibt. ...
wie schon von molily und Struppi bemerkt, willst Du das nicht wirklich;
und es gibt sehr gute gruende, soetwas nicht zu implementieren.
schon die sprachkernobjekte [[Boolean]], [[Number]] und [[String]]
haben ihre berechtigung sowohl als konstruktoren von instanzen des
jeweiligen objekttyps ([Boolean], [Number] und [String]
) als auch
als *typecast*-funktionen, die jegliche ihnen zugefuehrte objekte
bzw. primitive werte in die wiederum primitiven werte [boolean],
[number] bzw. [string] zwingen.
~~~javascript
var num1 = new Number(20); alert(typeof num1); // "object"
var num2 = Number("20"); alert(typeof num2); // "number"
var num3 = Number(num1); alert(typeof num3); // "number"
alert(num1 == num2); // true - impliziter typecast von "==".
alert(num1 === num2); // false - "===" unterdrueckt typecasting.
alert(num2 == num3); // true - war zu erwarten - werte sind gleich.
alert(num2 === num3); // true - werte sind eben auch vom gleichen typ.
[num1] unterscheidet sich von [num2] und [num3] betraechtlich.
[num1] ist zwar zu [num2] und [num3] wert- aber nicht typgleich.
[num2] und [num3] hingegen sind sowohl wert- als auch typgleich.
zurueck zum thema - da es diesen dualismus wie man sieht schon (und
auch berechtigterweise) gibt, ist davon abzuraten, konstruktoren
selbstgestrickter objekttypen anders als die oben beispielhaft
angefuehrten zu implementieren.
dies liefe nicht nur entgegen der erwartungshaltung eines mit der
sprachspezifikation vertrauten anwenders, sondern verbaute auch
den gewuenschten effekt, dass funktional angewandte konstruktoren
der typwandlung dienten.
und es gibt durchaus objekte, die bei berechnungen oder vergleichen
implizit auf eigene bzw. von `[[Object]]`{:.language-javascript} bzw. anderweitig vererbte
`[valueOf]`{:.language-javascript} bzw. `[toString]`{:.language-javascript} methoden zugreifen.
eine in jeglicher hinsicht aesthetisch implementierte konstruktor-
funktion traegt diesem umstand dort, wo es notwendig erscheint
rechnung, indem sie einen geeigneten primitiven wert zurueckgibt.
links ...
- theoretisch unterstuetzend : [»Funktion nicht als Konstruktor«](http://groups.google.com/group/de.comp.lang.javascript/browse_frm/thread/445e720541c03165/35818a7259c326e4?lnk=st&q=#35818a7259c326e4)
- durch die praxis untermauert: [»*Echte*Number-Instanzen können doch mit eigenen Methoden rechnen«](http://forum.de.selfhtml.org/archiv/2008/5/t171732/#m1125422)
so long - peterS. - pseliger@gmx.net
--
»Because objects in JavaScript are so flexible, you will want to think differently about class hierarchies.
Deep hierarchies are inappropriate. Shallow hierarchies are efficient and expressive.« - [Douglas Crockford](http://javascript.crockford.com/)
[ie:( fl:) br:> va:( ls:& fo:) rl:) n3;} n4:} ss:} de:µ js:} mo:? zu:\]](http://www.peter.in-berlin.de/projekte/selfcode/?code=ie%3A%28+fl%3A%29+br%3A%3E+va%3A%28+ls%3A%26+fo%3A%29+rl%3A%29+n3%3B%7D+n4%3A%7D+ss%3A%7D+de%3A%B5+js%3A%7D+mo%3A%3F+zu%3A%5D)