2013-03-16 90 views
6

我在原型中保存了一個屬性_data,作爲所有創建對象的定義。javascript原型繼承 - 共享屬性

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

現在從A創建的所有對象都具有財產_data

我想要原型繼承,原型的_data將有原型鏈中所有原型的_data值。

不知道直接的方法,在這個例子中我使用了一個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 = []; 

當我創建具有值aa對象a並用值bb對象bb.get()返回[aa, bb]。如果原型A_data將延長爲aaaa,函數b.get()返回[aa, aaaa, bb]

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] 

這是一個很好的(標準)方法如何實現這一目標?我的意思是使用構造函數校正,而Object.create和參考父母原型與constructor.prototype

這裏是一個演示:http://jsfiddle.net/j9fKP/

原因這一切都是在ORM圖書館,方案的繼承方案允許字段定義。子計劃必須具有來自父計劃的所有字段。

+0

[作爲數組原型的Javascript對象成員可能被所有類實例共享]的重複(http://stackoverflow.com/questions/4425318/javascript-object-members-that-are-prototyped-as-arrays -become-shared-by-all-cla) – Bergi 2013-06-28 03:36:32

回答

1

我想要原型繼承,原型的_data將有原型鏈中所有原型的_data值。

這是另一回事。 「原型繼承」意味着如果當前對象上有一個_data屬性,則不會在鏈中進一步查看。此外,它似乎是一種issue with nested objects,雖然我不知道你真的想要什麼。但是,如果實際上想要連接它們,讓數組對象繼承另一個數組幾乎沒有什麼意義。

所以我認爲你的getter真的很好。

這是一個很好的(標準)方法嗎?我的意思是用構造校正,同時的Object.create和參考父原型constructor.prototype

構造函數修正是好的,但actually quite useless(特別是如果你希望符合標準的Object.create)。

但是,在this.__proto__.constructor.prototype中,.__proto__.constructor.prototype是冗餘的。既然兩者都是非標準的,或者需要構造器校正,則應該使用標準Object.getPrototypeOf() function來獲取原型對象。

通過以下非常通用的解決方案,您可以嵌套繼承(A.原型,B原型,B型實例......)任意深。一切從A.prototype繼承將具有add方法,其增加了_data到當前對象,並橫穿所述原型鏈和收集所有_data一個get方法:

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 

實例:

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

真的不錯的代碼!與getPrototypeOf並且也忘記了實例_data屬性。非常感謝你提供了很好的解釋和例子。正是我需要的。 – opio 2013-03-16 14:43:38

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

我最近編輯的問題很抱歉,a.get()應該只返回[aa,aaaa]。謝謝 – opio 2013-03-16 14:47:09

+0

我知道,這就是我的代碼。 – zeroflagL 2013-03-16 14:49:15

1

我覺得我有更好的理解你現在要做的事情,所以我刪除了我早先的答案,並張貼這一個。

這裏就是我想我會做(與我不能肯定這與更好理解,一個完全不同的方法會不會更好的警告):

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

這樣,B沒有達到過深入A的內部。

+0

是不是'_Adata'是「一個內部」?你可以(和imo應該)使用A的'get'。 – Bergi 2013-03-16 14:30:18

+0

@Bergi:是的,我猜你可能會認爲它是。對我來說,其中的重點是分享這些信息,所以我不認爲它們是「內部的」,並且調用'A'的'get'版本是沒有輔助函數庫的痛苦。但我已經添加了它作爲一個選項。 – 2013-03-16 14:32:45