ich werkel schon seit einiger Zeit an ein Javascript Klassenframework und ich denke ich bin allmählich so weit, das ich es einmal vorstellen möchte und gerne eure Meinung dazu hören würde.
Über das Thema schreib ich seit längeren an einem Artikel, beiß' ich mir aber seit einem halben Jahr die Zähne daran aus. Mir scheint es, es gibt keine wirklich sinnvolle Lösung für einen sauberen OOP Ansatz in JS. Mathias hat letztens auch darüber etwas geschrieben http://molily.de/weblog/javascript-pseudoklassen bzw. auch hier.
Es gibt also 3. Wege
1. den klassischen über eine normale Objekteigenschaft, so wie du es löst. Ist aber im Endeffekt ein vorgaukeln und birgt die Gefahr des überschreibens des Wertes.
2. Wie es Mathias vorschlägt, die Kennzeichnung als private Variabel anhand eines suffix. Das erschwert zumindest das Überschreiben.
3. oder die Kapselung im Konstruktor. Das bringt aber Geschwindigkeitseinbußen mit sich.
Was mich ein wenig stört, ist die Verwendung der Bezeichnung private, obwohl hier nichts privat ist. Das ist wohl ein ähnlicher Ansatz wie joose?
Ich wollte jetzt mal die Geschwindigkeit vergleichen. Ich hatte mir für meinem Artikel einen Benchmark geschrieben mit dem ich die verschiedenen Ansätze teste. Momentan Mootools, Jooes, mein eigener und das pure JS.
Der Test sieht in JS so aus:
var JS = {name:'js'};
(function() {
var gID = 0;
function A() {
var privat = gID++;
var myA = 0;
this.a = function(a) {
if(a) myA = a;
return myA + '(' + this.name() +')';
};
this.ID = function() {return privat;};
this.name = function() {
return 'A(' + this.ID() + ')';
}
this.parent = function() {
return 'not able';
};
}
A.prototype = {
b: function() { return 'A->b() ' + this.name();},
c: function() { return 'A->c() ' + this.name();},
d: function(p1) { return p1 + ' A->d() Name:' + this.name(); },
e: function() { return ' A->e() ';}
}
function B() {
A.call(this);
}
B.prototype = new A();
B.prototype = {
c: function() { return 'B->c() '+ A.prototype.c.call(this) ;},
d: function(p1, p2) { return p1 + ' B->d() ' + A.prototype.d.call(this, p1, p2) ;}
}
function C() {
B.call(this);
}
C.prototype = new B();
C.prototype = {
d: function(p1, p2) { return p1 + ' C->d() ' + B.prototype.d.call(this, p1, p2);}
}
JS.B = A;
JS.C = B;
JS.D = C;
})();
und folgender Testcode:
function _debug(txt) {
var o = document.getElementById('debug');
o.innerHTML += txt + '\n';
}
var c1 = new JS.C();
var c2 = new JS.C();
var d = new JS.D();
c1.a('c1');
c2.a('c2');
_debug( d.d('halllo', 2) );
_debug('ich bin ' + c1.name());
_debug('ich bin ' + c2.name());
_debug('mein c() ist: ' + c2.c());
_debug('mein a() ist: ' + c1.a());
_debug('mein a() ist: ' + c2.a());
_debug('mein a() ist: ' + d.a());
Die Ausgabe ist:
halllo C->d() halllo B->d() halllo A->d() Name:A(4)
ich bin A(2)
ich bin A(3)
mein c() ist: B->c() A->c() A(3)
mein a() ist: c1(A(2))
mein a() ist: c2(A(3))
mein a() ist: 0(A(4))
Das würde ich gerne mit deinem Skript machen, aber ich krieg's nicht hin:
var JS_CLASS = {name:'js-class'};
(function() {
var gID = 0;
Object.extend('A', function() {
private.privat = gID++;
private.myA = 0;
public.a = function(a) {
this.a = a;
}
public.ID = function() {
return this.myA;
}
public.name = function() {
return 'A(' + this.ID() + ')';
}
public.b = function() { return 'A->b() ' + this.name();}
public.c = function() { return 'A->c() ' + this.name();}
public.d = function(p, p2) { return p + ' A->d() Name:' + this.name() + '.' + p2; }
public.e = function() { return ' A->e() ';}
});
A.extend('B', function(super) {
public.init = function() {
super('test');
}
public.c = function() {
return 'B->c() ' + super.c();
}
public.d = function(p1, p2) {
return p1 + ' B->d() ' + super.d(p1, p2) ;
}
});
B.extend('C', function(super) {
public.init = function() {
super('test');
}
public.d = function(p1, p2) {
return p1 + ' C->d() ' + super.d(p1, p2) ;
}
});
JS_CLASS.B = A;
JS_CLASS.C = B;
JS_CLASS.D = C;
})();
Ausgabe:
halllo C->d() halllo B->d() halllo A->d() Name:A(0).2
ich bin A(0)
ich bin A(0)
mein c() ist: B->c() A->c() A(0)
Dann komt eine Fehlermledung: c1.a is not a function
Offensichtlich kann man nicht, von C über B auf eine Funktion in A zugreifen. Da stimmt etwas mit der Vererbungskette nicht.
Struppi.