2013-03-16 11 views
6

Ich habe eine Eigenschaft _data im Prototyp als eine Definition für alle erstellten Objekte gespeichert.Javascript Prototyp Vererbung - gemeinsame Eigenschaft

function A() {} 
A.prototype._data = []; 

Nun werden alle von A erstellten Objekte haben Eigenschaft _data.

Ich möchte Prototyp Vererbung, wo _data Prototyp wird _data Werte von allen Prototypen in Prototyp-Kette haben.

Weiß nicht direkten Weg, in diesem Beispiel verwende ich einen Getter get().

function A() {} 

A.prototype._data = []; 

A.prototype.add = function(rec) { 
    this.__proto__._data.push(rec); 
} 

A.prototype.get = function() { 
    if(typeof this.__proto__.constructor.prototype.get == 'function') 
    { 
    return this.__proto__.constructor.prototype.get().concat(this.__proto__._data); 
    } 
    else 
    { 
    return this.__proto__._data || []; 
    } 
} 

function B() {} 
B.prototype = Object.create(A.prototype, { constructor: { value: B }}); 
B.prototype._data = []; 

Wenn ich Objekt erstellen a mit Werten aa und [aa, bb]b mit Wert bb, b.get() kehrt Objekt. Und später, wenn _data des Prototyps A mit aaaa erweitert wird, gibt die Funktion b.get()[aa, aaaa, bb] zurück.

var a = new A(), b = new B(); 

a.add('aa'); 
b.add('bb'); 
console.log(b.get()); // [aa, bb] 

a.add('aaaa'); 
console.log(b.get()); // [aa, aaaa, bb] 

// EDITED - _data in A prototype shoud be without B 
console.log(a.get()); // [aa, aaaa] 

Ist es ein guter (Standard) Weg, um dies zu erreichen? Ich meine mit Konstruktorkorrektur während Object.create und Referenz Elternprototyp mit constructor.prototype? Hier

ist eine Demo: http://jsfiddle.net/j9fKP/

Grund für all dies ist Felddefinition für Schema in ORM-Bibliothek, wo Vererbung von Systemen erlaubt. Kinderschema muss alle Felder vom Elternschema haben.

+0

mögliche Duplikate von [Javascript-Objekt-Member, die als Array prototypisiert werden, werden von allen Klasseninstanzen geteilt] (http://stackoverflow.com/questions/4425318/javascript-object-members-that-are-prototyped-as-arrays -become-shared-by-all-cla) – Bergi

Antwort

1

Ich würde Prototypvererbung mögen, wo _data von Prototypen _data Werte aus allen Prototypen in Prototypkette haben wird.

Das ist eine andere Sache. "Prototyp Vererbung" bedeutet, dass, wenn es eine _data Eigenschaft für das aktuelle Objekt gibt, es nicht weiter in der Kette suchen wird. Es scheint auch eine Art von issue with nested objects zu sein, obwohl ich nicht sicher bin, was du wirklich willst. Es wird jedoch kaum Sinn machen, ein Array-Objekt von einem anderen Array erben zu lassen, wenn Sie diese tatsächlich verketten wollen.

Also ich denke, Ihr Getter ist wirklich in Ordnung.

Ist es ein guter (Standard) Weg, dies zu erreichen? Ich meine mit Konstruktor Korrektur während Object.create und Referenzmutter Prototyp mit constructor.prototype

Constructor Korrektur schön, aber actually quite useless (vor allem, wenn Sie erwarten, dass ein standardkonforme Object.create).

In this.__proto__.constructor.prototype ist jedoch entweder .__proto__ oder .constructor.prototype redundant. Da beide entweder nicht standardisiert sind oder Konstruktorkorrektur erfordern, sollten Sie den Standard Object.getPrototypeOf() function verwenden, um Ihr Prototypobjekt zu erhalten.

Mit der folgenden sehr allgemeinen Lösung können Sie die Vererbung verschachteln (A.Proto, B-Proto, B-Instanz, ...) beliebig tief. Alles aus A.prototype vererben wird eine add Methode haben, die _data auf das aktuelle Objekt hinzufügt und eine get Methode, die die Prototypkette durchläuft und sammelt alle _data:

function A() { 
    // this._data = []; // why not? 
} 
A.prototype._data = []; // not even explicitly needed 
A.prototype.add = function(rec) { 
    if (! this.hasOwnProperty("_data")) // add it to _this_ object 
     this._data = []; 
    this._data.push(rec); 
} 
A.prototype.addToAllInstances = function(rec) { 
    Object.getPrototypeOf(this).add(rec); 
} 
A.prototype.get = function() { 
    var proto = Object.getPrototypeOf(this); 
    var base = typeof proto.get == 'function' ? proto.get() : []; 
    // maybe better: 
    // var base = typeof proto.get == 'function' && Array.isArray(base = proto.get()) ? base : []; 
    if (this.hasOwnProperty("_data")) 
     return base.concat(this._data); // always get a copy 
    else 
     return base; 
} 

function B() { 
    A.call(this); 
} 
B.prototype = Object.create(A.prototype, { constructor: { value: B }}); 
B.prototype._data = []; // not even explicitly needed 

Beispiel Nutzung:

var a = new A(); 
var b = new B(); 

a.add('ai'); 
a.get(); // [ai] 

a.addToAllInstances('ap'); // === A.prototype.add('ap'); 
a.get(); // [ap, ai] 
new A().get(); // [ap] 
b.get(); // [ap] 
b.prototype.get(); // [ap] 

b.add('bi'); 
b.get(); // [ap, bi] 

a.addToAllInstances('aap'); 
b.addToAllInstances('bp'); 
b.get(); // [ap, aap, bp, bi] 
+0

Wirklich schöner Code! mit getPrototypeOf und auch instance _data Eigenschaft. Vielen Dank für die ausgezeichnete Erklärung und das Beispiel. Genau das, was ich brauche. – opio

1
function A() {} 
    A.prototype._data = []; 

A.prototype.add = function(rec) { 
    this._data.push(rec); 
} 

A.prototype.get = function() { 
    return this._data; 
} 

function B() {} 
B.prototype = Object.create(A.prototype, { constructor: { value: B }}); 

B.prototype._data = []; 

B.prototype.get = function() { 
    return A.prototype._data.concat(this._data); 
} 

a.add('aa'); 
b.add('bb'); 
console.log(b.get()); // [aa, bb] 

a.add('aaaa'); 
console.log(b.get()); // [aa, aaaa, bb] 

Fiddle

+0

Es tut mir leid für die schlechte Frage, die ich in letzter Zeit bearbeitet habe, a.get() sollte nur [aa, aaaa] zurückgeben. Vielen Dank – opio

+0

Ich weiß, und das ist, was mein Code tut. – zeroflagL

1

Ich denke, ich habe ein besseres Verständnis was ich jetzt machen möchte, habe ich meine frühere Antwort gelöscht und poste diese.

Hier ist, wie ich glaube, ich würde es tun (mit dem Vorbehalt, dass ich bin nicht sicher, dass mit einem noch besser Verständnis, ein völlig anderer Ansatz wäre nicht besser sein):

function A() {} 
A.prototype._Adata = []; 

A.prototype.add = function(rec) { 
    this._Adata.push(rec); 
}; 

A.prototype.get = function() { 
    return this._Adata; 
}; 

function B() {} 
B.prototype = Object.create(A.prototype, { constructor: { value: B }}); 

B.prototype._Bdata = []; 

B.prototype.add = function(rec) { 
    this._Bdata.push(rec); 
}; 
B.prototype.get = function() { 
    return this._Adata.concat(this._Bdata); 
    // Or: return A.prototype.get.call(this).concat(this._Bdata); 
}; 

var a = new A(); 
var b = new B(); 

a.add('aa'); 
b.add('bb'); 
console.log(b.get()); // [aa, bb] 

a.add('aaaa'); 
console.log(b.get()); // [aa, aaaa, bb] 

Fiddle

auf diese Weise B nicht zu tief in A ‚s Einbauten erreicht.

+0

Ist '_Adata' nicht ein" A internal "? Sie könnten (und ich sollte) A's 'get' verwenden. – Bergi

+0

@Bergi: Ja, ich denke, du könntest argumentieren, dass es so ist. Für mich besteht der ganze Sinn darin, diese Informationen zu teilen, so dass ich sie nicht als "intern" betrachte und "A's Version von" get "zu nennen, ist ein Schmerz ohne eine Helferbibliothek. Aber ich habe es als eine Option hinzugefügt. –