2012-08-15 172 views
1

我怎麼能在運行時爲每個實例覆蓋this.property,未做一個新的類,並最終調用父doAnotherThing的Javascript原型banals:繼承

var ThridPartyObject = function() { 

    this.property = 'value'; 

    this.doOneThing= function() { /* */ } 

    this.doAnotherThing= function() { /* */ } 
}; 

沒有運氣:

ThridPartyObject.prototype = { 

    property: 'myvalue', 

    doOneThing: function() { // Override only this function and call the other 
     return this.doAnotherThing(); 
    } 

}; 

編輯:忘了說,property可能會或可能不會存在。

我需要這個,因爲在Backbone.js的,我必須定義一個自定義屬性爲我所有的模型實例,以及一些功能應該在原有骨幹的人以不同的方式行事。這裏是骨幹如何定義一個Backbone.Model_.extend是underscore.js):

var Model = Backbone.Model = function(attributes, options) { 
    var defaults; 
    attributes || (attributes = {}); 
    if (options && options.collection) this.collection = options.collection; 
    if (options && options.parse) attributes = this.parse(attributes); 
    if (defaults = getValue(this, 'defaults')) { 
     attributes = _.extend({}, defaults, attributes); 
    } 
    this.attributes = {}; 
    this._escapedAttributes = {}; 
    this.cid = _.uniqueId('c'); 
    this.changed = {}; 
    this._silent = {}; 
    this._pending = {}; 
    this.set(attributes, {silent: true}); 
    // Reset change tracking. 
    this.changed = {}; 
    this._silent = {}; 
    this._pending = {}; 
    this._previousAttributes = _.clone(this.attributes); 
    this.initialize.apply(this, arguments); 
    }; 

    // Attach all inheritable methods to the Model prototype. 
    _.extend(Model.prototype, Events, { 
     // cut 
    }); 

回答

2

如果對象是真正的「第三方」,和你的控制範圍之外,那麼它的創造者選擇的模式是不兼容原型繼承(有時稱爲「封閉模式」)。你將無法覆蓋,全球ThirdPartyObject實例的任何屬性,因爲每個ThirdPartyObject得到propertydoOneThingdoAnotherThing新的施工時間分配給它。

在這種情況下,唯一的解決辦法是建立一個新的工廠函數包裝原始:

function modifiedThirdPartyObjectFactory() { 
    var x = new ThirdPartyObject(); 
    x.property = "myvalue"; 
    return x; 
} 

var mtpo = modifiedThirdPartyObjectFactory(); 

某一模式的確實使用原型繼承會的工作如下:

function ThirdPartyObject() { 
    this.property = "value"; 
} 

ThirdPartyObject.prototype.doOneThing = function() { 
}; 

ThirdPartyObject.prototype.doAnotherThing = function() { 
}; 

這種模式設置實例性能,通常的數據,在利弊tructor。而共享屬性,通常的方法,繼續原型。原始代碼使全部爲屬性實例屬性,因此沒有可以修改的共享屬性,這會導致您的更改反映在所有實例中。

+0

假設好的(第二...),我怎麼能從doOneThing裏面調用doAnotherThing? – Polmonino 2012-08-15 22:57:12

+0

'this.doAnotherThing()'將起作用。 – Domenic 2012-08-15 22:59:20

+0

我做你的例子(函數覆蓋),這完全消滅了原來的類...意味着現有的實例調用不再工作... – Polmonino 2012-08-15 23:20:49

1

你實際上正在考慮向後。

原型就像父類一樣。 這不完全,像基於類的語言父類(有很大的分歧)。
但在這種情況下,爲了繼承屬性/方法,原型將是父類。

當您製作Foo時,Foo是您的問題中的所有意圖和目的的孩子。 當你這樣做:

function Foo() { this.method = function() {}; this.property = {}; } 
Foo.prototype.method = function() {}; 
Foo.prototype.property = {}; 
Foo.prototype.other_property = 3; 

它類似於說:

PrototypeClass { 
    public virtual property = {}; 
    public other_property = 3; 
    public virtual method () { } 
} 
Foo inherits BaseClass { 
    public override property = {}; 
    public override method() {} 
} 

var foo = new Foo(); 

constructorFooprototype,具有相同的名字覆蓋了一切鏈。 當Foo有一種方法或在其內部的屬性,THEN它看起來上游,通過其inheritance/prototype鏈。

所以,如果要覆蓋的Foo方法/屬性,那麼你MUST覆蓋了的new Foo()實例。

你對於那些非常簡單,只是構建一個包裝圍繞Foo選項......這樣的:

function FooPlusPlus() { 
    var foo = new Foo(); 
    foo.plus = function() { this.doSomething(); console.log(this.val); }; 
    foo.plusPlus = function() { foo.plus(); console.log(this.other_val); }; 
    return foo; 
} 

var fooPlusPlus = FooPlusPlus(); // ***NO NEW*** 

...或者創建簡單地擴展預先存在的對象的函數(無論它是一個「類」或與要他們延長任何添加的屬性/功能「字典」或功能,或數組):

var extendObj = function (subject, extensions) { 
    var key = ""; 
    for (key in extensions) { if (extension.hasOwnProperty(key)) { 
     subject[key] = extensions[key]; 
    }} 
} 


var regularFoo = new Foo(); 

extendObj(regularFoo, { awesomeFunc : function() { if (typeof this.doSomething === "function") { this.doSomething(); }}, coolProp : "Bob" }); 

JS給你自由,讓任何繼承什麼,只要你不期望字符串或數字像使用自定義數據的類一樣行動,而不用仔細操作Core對象。