donp: Unobtrusive Prototyping?

Beitrag lesen

Tach auch,

Habe mich extra vorsichtig ausgedrückt mit "Ein Ansatz wäre vielleicht". Ein bisschen eigenen Hirnschmalz musst du schon noch dazugeben...

Wenn ich das richtig sehe, würde ich so aber mit einer Kopie von document.body arbeiten, nicht mit einer Referenz auf document.body. [...] verändere ich aber etwas in der Kopie, ändert sich das nicht in der original-Instanz.

Das siehst du völlig richtig. Ich schrub ja: es wird ein *neues* Objekt erzeugt. Dieses ist immerhin billig zu haben, denn wenn es eine Eigenschaft oder Methode nicht selbst hat, zeigt es einfach diejenige vom Original-Objekt vor. Es ist also nicht wirklich eine Kopie. Das ist der Clou der prototypischen Vererbung.

Man kann das neue Objekt nur deshalb gefahrlos erweitern, weil es eben gerade nicht das alte ist. Wäre es nur eine Referenz auf das alte, dann könnte man ja wieder dessen Methoden überschreiben, was du aber gerade verhindern willst.

Das ginge dann z.B. so...

  
// Test Objekt  
var MyOne =  
{  
    message: 'initial message from constructor',  
    alert: function(){ alert(this.message) }  
}  
var s = MyOne; // original-Instanz  
var t = s;     // abgeleitete Instanz  
t.alert = function(){ alert('Überschriebene Methode!') };  
s.alert();     // Ausgabe: Überschriebene Methode!  

...und wäre also nicht das, was man will.

Man *muss* also zwangsläufig mit einer "Kopie" arbeiten. Wenn man damit trotzdem direkt auf die Eigenschaften oder Methoden des Original-Objekts zugreifen will, muss man halt jeweils das prototype-Objekt ansprechen:

// Objekt-Ableiter nach http://javascript.crockford.com/prototypal.html

function object(o) {
        function F() {}
        F.prototype = o;
        return new F();
    }

// Test Objekt
function MyOne()
{
    this.message = 'initial message from constructor';
    this.alert = function(){ alert(this.message) };
}

// original-Instanz
var s = new MyOne();

// abgeleitete Instanz
var e = object(s);

// Attribut in original-Instanz manipulieren
s.message = 'new message from original instance';
e.alert(); // Ausgabe: »new message from original instance«

// Attribut in abgeleiteter Instanz ändern

e.proto.message = 'altered message from extended instance';

s.alert(); // Ausgabe: »altered message from original instance«
e.alert(); // Ausgabe: »altered message from extended instance«

// Attribut in original-Instanz manipulieren
s.message = 'newly altered message from original instance';
e.alert();  // Ausgabe: »newly altered message from original instance«

  
Wie du siehst, arbeitet man jetzt definitiv mit dem originalen Objekt.  
  

>   
> Mal ganz davon abgesehen bin ich über ein Phänomen gestolpert, was den Anwendungsbereich dieser Ableitungsgeschichte etwas reduziert:  
  
In der Tat werden die nicht iterablen Eigenschaften offenbar nicht weiterverebt. Auch dieses Problem lässt sich aber durch direktes Ansprechen des prototype-Objekts lösen:  
  

> ~~~javascript

var s = "hello world";  

> var e = object( s );  
> alert( s.length ); // Ausgabe: 11  

 alert( e.__proto__.length ); // Ausgabe: undefined

Hier klappt's nicht mal mit dem prototype-Objekt, aber mit...

  
String.prototype.obj=function(){function F(){}F.prototype=this;return new F();};  
// Allgemeiner: Object.prototype.newobj=function(){function F(){}F.prototype=this;return new F();};  
var e = s.newobj();  
alert( e.__proto__.length ); // Ausgabe: 11  

...hat man auch endlich Zugriff auf die nicht iterable length-Eigenschaft :).

var s = new String( "hello world" );

var e = object( s );
alert( s.length ); // Ausgabe: 11
alert( e.proto.length ); // Ausgabe: 11

  
Du darfst also String erweitern, gelle?  
  

> ~~~javascript

var s = [1,2,3];  

> var e = object( s );  
> alert( s.length ); // Ausgabe: 3  
> alert( e.length ); // Ausgabe: 3

oha, Arrays darf ich also vergewaltigen, interessant.

"vergewaltigen" ist aber ein hartes Wort für eine so schöne Sache...

var s = new Number(123.45);
var e = object( s );
alert( s.toFixed() ); // Ausgabe: 123
alert( e.proto.toFixed() ); // Ausgabe: 123

  
Number funktioniert somit auch korrekt.  
  

> scheint wohl nett zu sein, wenn man eigene Objekte erweitern/vererben will, aber eher unbrauchbar, wenn man an Javascript-eigenem Kram spielen möchte.  
  
Tja, ob das alles besonders brauchbar ist, frage ich mich auch noch, deshalb meine vorsichtige Ausfrucksweise am Anfang. Habe ja auch nur mal einen Ansatz für deine Lieblingsvariante ausprobiert.  
  
Funktionieren würde es jedenfalls, aber man müsste dann halt dem Framework noch ein paar schlaue Spezialfunktionen mitgeben, die dafür sorgen, das man immer das das richtige prototype-Objekt erwischt. Diese habe ich dir hier noch nicht vorgekaut, habe bis jetzt selber nur einen recht blassen Schimmer davon, wie sie aussehen müssten...  
  
Gruß, Don P