2011-04-22 84 views
0


我是js OO編程的新手,我無法找到此錯誤的解決方案。 我聲明下面的類層次結構:父類的方法在javascript中的子類中未定義

function FML_Field(id){ 
    this.id= id; 
    this.optional= true; 
    this.node= null; 

    if(this.id === undefined){ 
     throw ""; //should provide Id; 
    } 

    var this.node= document.getElementById(this.id); 
    if(this.node === null){ 
     throw ""; 
    } 

    this.setAsOptional= function(){ 
     this.optional= true; 
    }; 
    this.setAsRequired= function(){ 
     this.optional= false; 
    }; 
    this.isOptional= function(){ 
     return this.optional; 
    }; 
} 

及其兒子:

function FML_Text(id){ 
    this.prototype= new FML_Field(id); 
    FML_Text.prototype.constructor= FML_Text; 
    this.maxLength= false; 
    this.minLength= false; 

    this.setMaxLength= function(maxLength){ 
     this.maxLength= maxLength; 
    } 
    this.getMaxLength= function(){ 
     return this.maxLength; 
    } 
    this.hasMaxLength= function(){ 
     return this.maxLength !== false; 
    } 
} 

然後我用下面的代碼進行:

var first_name = new FML_Text("first_name"); 
first_name.setAsRequired(); /*throws an error: setAsRequired is not defined*/ 

有什麼不對?我已經檢查了JavaScript控制檯:first_name被定義,但setAsRequired()不是。像first_name.setMaxLength()這樣的函數調用沒有問題。

預先感謝您。

預先感謝您

+0

我可以指點你這個StackOverflow的答案嗎?我相信它會幫助您更多地瞭解JavaScript OOP。這是非常好的和exaustive:http://stackoverflow.com/questions/1595611/how-to-properly-create-a-custom-object-in-javascript – dmarucco 2011-04-22 08:44:54

回答

0

這不是你如何設置繼承:

function FML_Text(id){ 
    this.prototype= new FML_Field(id); 
    // ... 
} 

所有這一切確實是創建一個名爲prototype在實例屬性。

它的完成這樣的:

function FML_Text(id){ 
    // ... 
} 
FML_Text.prototype = new FML_Field(); 

...你不能id參數傳遞到它,因爲它發生在子對象的構造函數被調用之前。相反,通常情況下,定義一個「初始化程序」函數,您的層次結構中的每個級別都支持後期構建,並調用該函數。

這是它的基礎,無論如何,但真正強大的繼承需要更多的工作。例如,實際上調用父類的孩子也定義的函數版本(例如,一個常用的初始化方法,或任何時候孩子專門化父方法)實際上是JavaScript中的一個小提琴,並且有還有一些其他的「陷阱」。但是通過一些管道工作,你可以獲得非常有效的繼承鏈(包括向父初始化者傳遞構造時參數)。

與其獨自飛行,您可能想要使用這種東西的現有實現之一。我在前面描述了我的this article,其中真的很有效調用父方法(「supercalls」)。 Prototype庫也提供了一個有效的「類」系統,雖然它是該系統的性能(和兼容性)的問題,導致我執行上述文章。 Dean Edwards也寫了很多關於這個問題的文章,並且John Resig已經投入使用。幾年前,當我看到他們時,我遇到了問題,但可能有更新。

事情找(在我看來):

  • 簡單,聲明式語法。
  • 語法非常友好,您的類有私有靜態成員實現的東西,不需要公開。 (私人實例方法可以在幾乎任何系統中完成,但是它們很昂貴;請參閱Crockford's discussion其中的幾種方法和my comparison的各種實現方法。)
  • 系統應該而不是依靠函數反編譯(使用Function實例的toString方法)。 Prototype和Resig都這麼做,我不知道愛德華茲的''和愛德華茲'一樣。功能反編譯從未標準化,並且在某些移動瀏覽器上無法使用。 (在Resig和Edwards的版本中,toString調用是隱含的,因此它有點難以找到,但它在那裏:它們將函數實例傳遞到正則表達式測試中,它將隱式地調用函數的toString。)
  • 系統應當而不是當調用實例方法時,只有在定義類時(如果有的話)纔會創建新的函數對象。原型的,每次您調用一個實例方法,可能需要調用其父版本(其魔術$super參數)。他們的機制使得它很容易使用父母的版本,但是無論您是否實際致電$super,在每次致電上創建新功能的代價(再次)都是如此。
+0

非常感謝你,這是一個非常好的和完整的答案。我會更多地關注OOP javascript,看起來像一團糟! – 2011-04-22 10:10:55

+0

@travelingsaleswoman:不用擔心,很高興幫助。我不會說這是一團糟。 JavaScript具有非常強大而靈活的OOP功能;這種靈活性有時可能具有挑戰性直到最近,調用父級版本的方法還存在一個實際問題。 ECMAScript(JavaScript)的第5版現在只有18個月的時間,它增加了一些可能會使* *更容易超級呼叫的事情,但實現要趕上規範需要時間。我會更新我的文章,在某些時候談論這些(不是很快)。 – 2011-04-22 10:27:18

+0

Coffeescript提供了傳統的OOP繼承模型,您可能需要考慮移植到coffeescript或者可能檢查爲其類定義生成的輸出 – timoxley 2011-10-13 12:06:47