Private/Public/Privileged Methoden & Speichernutzung
mrjerk
- javascript
Hallo zusammen,
Ich bin vor kurzem auf eine (zugegeben eher theoretische) Frage gestossen, und ich hoffe, der eine oder andere JS-Freak weiss hier eine Antwort.
Wenn ich eine "JavaScript-Klasse" (ja ich weiss, im strengen Sinne gibt es das in JS nicht) implementieren möchte, und eine Public-Methode dazu, mache ich das für gewöhnlich so:
function MeineKlasse() {
...
}
MeineKlasse.prototype.publicMethode = function () {...}
var meineInstanz = new MeineKlasse();
usw.
Eine "Private-Methode" baue ich mit Closures:
function MeineKlasse() {
var privateMethode = function () {...}
}
Soweit so gut. Was mache ich aber, wenn meine Private-Methode von einer Public-Methode aufgerufen werden soll? Dann geht das nach meinem Dafürhalten nur so:
function MeineKlasse () {
var privateMethode = function () {...}
this.publicMethode = function () {privateMethode();}
}
Auf dieser Seite wird dieses Konzept "priviligierte Methode" gennant.
Meine Fragen sind nun:
1.) Habe ich bei diesem Konzept nicht das Problem, dass bei jeder Instanz von MeineKlasse() ein neues Funktionsobjekt für die publicMethode angelegt wird? Ich habe mal vor Urzeiten in einer ActionScript-Doku gelesen, dass das so ist, und dass man deshalb Methoden wenn irgend möglich über das Prototyp-Attribut definieren soll, weil dann immer die gleiche Methode referenziert wird (was im o.g. Fall aber ja nicht geht) - ich weiss aber nicht ob das in JavaScript auch (noch) so ist.
2.) Wenn das tatsächlich so ist (dass jede Instanz das Funktionsobjekt neu erzeugt), verschwende ich bei vielen Instanzen ja ganz schön Speicher - wie entkomme ich diesem Dilemma?
Viele Grüße & Danke für Antworten,
Jörg
Hallo zusammen,
Ich bin vor kurzem auf eine (zugegeben eher theoretische) Frage gestossen, und ich hoffe, der eine oder andere JS-Freak weiss hier eine Antwort.Wenn ich eine "JavaScript-Klasse" (ja ich weiss, im strengen Sinne gibt es das in JS nicht) implementieren möchte, und eine Public-Methode dazu, mache ich das für gewöhnlich so:
function MeineKlasse() {
...
}
MeineKlasse.prototype.publicMethode = function () {...}
var meineInstanz = new MeineKlasse();
usw.
>
> Eine "Private-Methode" baue ich mit Closures:
>
> ~~~javascript
> function MeineKlasse() {
> var privateMethode = function () {...}
> }
>
Soweit so gut. Was mache ich aber, wenn meine Private-Methode von einer Public-Methode aufgerufen werden soll? Dann geht das nach meinem Dafürhalten nur so:
Javascript ist... Müll. Mächtiger Müll, aber Müll. Verabschiede dich von "private" und "public", du musst bei Javascript einfach anders denken und nicht versuchen deine z.B. Java oder C++ Kenntnisse 1:1 zu übertragen.
2.) Wenn das tatsächlich so ist (dass jede Instanz das Funktionsobjekt neu erzeugt), verschwende ich bei vielen Instanzen ja ganz schön Speicher - wie entkomme ich diesem Dilemma?
Und hör auf dir über soetwas den Kopf zu zerbrechen. Was macht das bisschen Speicher schon? Oder entwickelst du ein Framework oder etwas ähnliches, was von vielen Leuten eingesetzt wird?
Hallo,
Und hör auf dir über soetwas den Kopf zu zerbrechen. Was macht das bisschen Speicher schon?
Wie ich schon schrieb, meine Frage ist eher theoretischer Natur - ich würde gerne wissen, wie man das Problem sauber lösen müsste, falls das möglich ist. Dass das im konkreten Anwendungsfall dann ggf. keine Rolle spielt ist mir auch klar.
Oder entwickelst du ein Framework oder etwas ähnliches, was von vielen Leuten eingesetzt wird?
Konkret aufgetaucht ist die Frage in einem Projekt, wo es zwar nicht darum geht, ein großes Framework zu bauen, wohl aber um eine Codebasis, die von mehreren Frontend-Entwicklern genutzt wird, und innerhalb davon um eine Bibliothek, die an verschiedenen anderen Stellen im Code verwendet wird. Deswegen möchte ich den Code schon möglichst intuitiv und gut lesbar halten.
Viele Grüße,
Jörg
Javascript ist... Müll. Mächtiger Müll, aber Müll.
Ach so. Bist du hier eigentlich noch aus einem anderen Grunde als zu trollen?
Verabschiede dich von "private" und "public", du musst bei Javascript einfach anders denken
Und wie muss ich bei JavaScript denken? Verrate es uns.
Mathias
Hallo,
Verabschiede dich von "private" und "public", du musst bei Javascript einfach anders denken
Und wie muss ich bei JavaScript denken? Verrate es uns.
ich denke er möchte damit zu bedenken geben dass es nur bedingt sinnvoll ist, Features, die man von anderen Sprachen kennt (und dort nativ unterstützt werden) nachbauen/ahmen zu wollen - irgendwo muss man ggf. doch Abstriche machen, vom evtl. Zusatzaufwand ganz zu schweigen. Stattdessen sollte man sich die Eigenheiten von JavaScript zu Nutze machen. Oder sich für eine andere Programmiersprache entscheiden.
Gruss,
Worf
Hallo,
Verabschiede dich von "private" und "public", du musst bei Javascript einfach anders denken
Und wie muss ich bei JavaScript denken? Verrate es uns.ich denke er möchte damit zu bedenken geben dass es nur bedingt sinnvoll ist, Features, die man von anderen Sprachen kennt (und dort nativ unterstützt werden) nachbauen/ahmen zu wollen - irgendwo muss man ggf. doch Abstriche machen, vom evtl. Zusatzaufwand ganz zu schweigen.
Das ist schon richtig, aber erklärt nicht, warum man sich bei bei JavaScript von private und public verabschieden soll. Inwiefern bekannte OOP-Pattern auf JavaScript übertragbar sind, ist hinreichend erforscht. Es gibt ganze Bücher darüber.
JavaScript hat mit Konstruktoren, Prototypen und Instanzen ein Pattern, dass Klassen sehr nahe kommt. In ECMAScript 5.1 gibt es keine Einschränkung der Sichtbarkeit für Objekteigenschaften, das ist alles.
Stattdessen sollte man sich die Eigenheiten von JavaScript zu Nutze machen.
Verschachtelte Funktionen und Closures, um private Daten zu erreichen, sind Eigenheiten von JavaScript. Es spricht nichts prinzipielles dagegen.
Mathias
Javascript ist... Müll. Mächtiger Müll, aber Müll.
Ach so. Bist du hier eigentlich noch aus einem anderen Grunde als zu trollen?
Ich bin nunmal kein Roboter. Manchmal wird man einfach emotional. ;)
Verabschiede dich von "private" und "public", du musst bei Javascript einfach anders denken
Und wie muss ich bei JavaScript denken? Verrate es uns.
Das können andere besser als ich und das weißt du.
http://javascript.crockford.com/javascript.html
Inbesondere die Links im letzten Abschnitt.
Hallo,
1.) Habe ich bei diesem Konzept nicht das Problem, dass bei jeder Instanz von MeineKlasse() ein neues Funktionsobjekt für die publicMethode angelegt wird?
Ja.
Es werden zwei neue Funktionsobjekte angelegt, eins für die »private« Funktion (eine lokale Variable im Konstruktor) und eines für die Instanzmethode (die als Closure wirkt).
Ich habe mal vor Urzeiten in einer ActionScript-Doku gelesen, dass das so ist, und dass man deshalb Methoden wenn irgend möglich über das Prototyp-Attribut definieren soll, weil dann immer die gleiche Methode referenziert wird (was im o.g. Fall aber ja nicht geht) - ich weiss aber nicht ob das in JavaScript auch (noch) so ist.
Ja, das gilt auch für JavaScript. (ActionScript 2 ist eine ECMAScript-3-Implementierung, JavaScript basiert ebenfalls auf ECMAScript.)
Prototypische Delegation erlaubt es, die Fähigkeiten von anderen Objekten zu nutzen, anstatt sie zu kopieren. Effektive Privatheit ist in JavaScript aber nur über Funktions-Scopes möglich. Siehe meine JavaScript-Doku:
Organisation von JavaScripten: Module und Kapselung
Organisation von JavaScripten: Konstruktoren, Prototypen und Instanzen
Insbesondere:
Nachteile von privaten Objekten
Wozu Kapselung gut ist und wann sie nötig ist
2.) Wenn das tatsächlich so ist (dass jede Instanz das Funktionsobjekt neu erzeugt), verschwende ich bei vielen Instanzen ja ganz schön Speicher
Ja, richtig.
Die JavaScript-Engine kann das ggf. optimieren, weil der Code der Funktion immer derselbe ist, lediglich die Scope-Chain ändert sich. Aber im Grunde stimmt es, dass hier unzählige gleiche Funktionsobjekte erzeugt werden.
Wenn man effektive Privatheit von Daten haben will, führt nichts daran vorbei, als mit verschachtelten Funktionen zu arbeiten. Das ist nicht die nicht schnellste und sparsamste Möglichkeit, aber es führt nicht notwendig zu merklichen Performance-Einbußen. Es ist immer die Frage, wie oft und wie häufig du diesen Code aufrufst und wie viel Platz die Funktionen im Speicher wirklich brauchen. Ich würde behaupten, dass du selbst in einer großen JavaScript-Anwendung in aktuellen Browsern keine Performance-Nachteile spürst, wenn du nicht gerade Millionen Instanzen erzeugst.
Natürlich ist das Erzeugen von Instanzen mit solchen »privaten« Funktionen tausendmal langsamer als mit öffentlichen. Aber diese Operationen steht in keinem Verhältnis zu anderen üblichen Operationen in JavaScript-Anwendungen. Jede noch so einfache DOM-Operation wird tausendmal langsamer sein als das Anlegen einer Millionen Funktionen. Auf älteren Browsern oder Geräten mit begrenztem Speicher kann es natürlich anders sein.
Die schnellste und sparsamste Methode wäre die Nutzung von pseudo-privaten Methoden, die nicht effektiv privat sind, sondern Eigenschaften des Prototype. Sie werden bloß per Konvention nicht von außerhalb aufgerufen. Der Name solcher Methoden beginnt üblicherweise mit dem Unterstrich.
Generell gilt: Don’t optimize prematurely. Wenn ein JavaScript langsam läuft oder zuviel Speicher verbraucht, sollte man es profilen und die Stellen optimieren, die am langsamsten laufen bzw. am meisten Speicher belegen. Es ist möglich, aber unwahrscheinlich, dass solche privaten Funktionen die Performance-Bremsen in einer JavaScript-Anwendung sind.
Siehe auch meinen Artikel Performance von JavaScript-Closures.
Mathias
Hallo Molily,
Herzlichen Dank für diese ausführliche Antwort. Deine verlinkten Artikel zu dem Thema finde ich beim ersten Überfliegen sehr spannend, die werde ich mir mal in Ruhe zu Gemüte führen, wenn ich etwas mehr Zeit habe.
Danke & viele Grüße,
Jörg