2010-08-08 75 views
2
<disclaimer> 
What follows is the fruits of a thought experiment. What I'm doing 
isn't the issue; the symptoms are. Thank you. 
</disclaimer> 

我終於在JavaScript中包裝了構造函數,原型和原型繼承的頭部。但低於錯誤我的樣品中SomethingSpectactular方法:Baffling JavaScript繼承行爲

function FinalClass() {  
    return { 
     FinalFunction : function() { return "FinalFunction"; }, 
     TypeName : "FinalClass", 
     SomethingSpectacular : function() { 
      return FinalClass.prototype.SubFunction.call(this); 
     } 
    } 
} 
FinalClass.prototype = new SubClass(); 
FinalClass.constructor = FinalClass; 

var f = new FinalClass(); 

的原因這個錯誤我是:

  1. 的JavaScript 顯然不掃描原型鏈以同樣的方式進行的方法,因爲它不爲屬性。即,f.SubFunction()生成錯誤。
  2. 要想在原型上找到方法,每次要執行此操作時都必須至少進行3次點操作。 FinalClass DOT原型DOT Subfunctino DOT調用。你明白了。
  3. 基本類(原型)方法沒有以我期望的方式顯示在Intellisense中。這非常煩人。

所以思考的經驗是確定如果我寫了一個版本的inherits將stub函數插入到爲您委派回原型的子類中會發生什麼。例如,它會自動創建下面的函數,並把它添加到FinalClass

function SubFunction() { SubClass.prototype.SubFunction.call(this); } 

現在,我已經得到了剛纔的一切映射出和工作。作爲Object.prototypeFunction.prototype的擴展的inherits方法以Function作爲其唯一參數。這是基礎類。子類是通過分析Object.prototype.inherits.caller來確定的。

從那裏,我設置了子類上的prototypeconstructor,然後開始分析子類新原型上的方法。我在原型和基類的公共接口上構建一個包含方法的數組。最終結果是一個很好的數組,其中包含通過原型或基類構造函數的return語句公開的方法。

一旦我有了,我開始尋找子類上的每個方法。如果它不在那裏,我將它添加到具有相同名稱和簽名的子類中。然而,該方法的主體只是將調用轉發給基類。

現在,我可以遍歷所有這些代碼,並且它可以很好地工作,直到我實例化子類的實例。那是當事情變得不可靠的時候。下面是我使用Visual Studio 2008(SP1)和Internet Explorer 8中觀察到:

  1. 此前實例,BaseClass不公開任何公共方法。這是可以預料的。通過類構造函數的return語句公開的方法在實例化之前不會顯示。我很好。
  2. 在實例化之前,​​公開了來自BaseClass的方法。這正是我所期望的。
  3. 一旦我宣佈BaseClass的實例,它擁有我期望的所有成員。它有它的typeNameBaseFunction方法。
  4. 一旦我聲明​​的實例,它只有那些由其構造函數的return語句返回的方法。沒有來自基類的成員。在將基類方法映射到子類的繼承方法中完成的所有工作似乎都已丟失。

對我來說,這裏最大的祕密就是在執行繼承期間我添加到子類中的方法消失了。在執行過程中,我可以清楚地看到SubClass正在被修改,並且BaseClass的函數正在被傳播。但是,當我創建SubClass的一個實例時,該信息不再存在。

我認爲這與構造函數,事件順序或其他我根本沒有看到的東西有關。

A最後注意:該項目是爲了理解JavaScript的複雜性以及它的原型繼承系統如何工作而設計的。我知道那裏有現有的圖書館。我知道我正在重新發明輪子。我正在有意地重新發明它。有時候,理解事物的最好方法是自己構建它。這已經是一次巨大的學習經歷,但我只是在這一點上難住。

守則

sti.objects.inherits = function inherits(baseClass) { 

    var subClass = sti.objects.inherits.caller; 

    var baseClassName = sti.objects.getTypeName(baseClass); 
    var methods = sti.objects.getMethods(baseClass); 

    if(!sti.objects.isDefined(baseClass.typeName)) 
     baseClass.typeName = baseClassName; 

    var subClass = sti.objects.inherits.caller; 
    var subClassName = sti.objects.getTypeName(subClass); 

    var temp = function() {}; 
    temp.prototype = new baseClass(); 

    subClass.prototype = temp.prototype; 
    subClass.constructor = subClass; 
    subClass.typeName = subClassName; 
    subClass.baseClass = baseClass.prototype; // Shortcut to the prototype's methods 
    subClass.base = baseClass; // Cache the constructor 

    for(var index = 0; index < methods.items.length; index++) { 
     var resource = methods.items[index].getFunction(); 
     var methodName = methods.items[index].getName(); 
     if(methodName != "" && ! sti.objects.isDefined(subClass[methodName])) { 
      var method = sti.objects.createOverride(baseClassName, resource); 
      subClass[methodName] = method; 
      if(typeof subClass.prototype[methodName] == "undefined") { 
       subClass.prototype[methodName] = method; 
      } 
     } 
    } 
} 

Object.prototype.inherits = sti.objects.inherits; 
Function.prototype.inherits = sti.objects.inherits; 

function BaseClass() { 
    return { 
     A : function A() {return "A";} 
    }; 
} 


function SubClass() { 
    inherits(BaseClass); 

    return { 
     B : function B() { return "B"; } 
    }  
} 

var b = new BaseClass(); 
var s = new SubClass(); 

回答

4

你的構造函數不工作的構造。當你使用新的關鍵字Javascript創建新的對象,並希望你的構造函數使用成員等填充它。你的構造函數正在返回另一個新的對象,而不是與構造函數的用法相關的對象,因此原型不起作用。

構造函數更改爲類似

function FinalClass() { 
    this.FinalFunction = function() { return "FinalFunction"; }; 
    this.TypeName = "FinalClass"; 
    this.SomethingSpectacular = function() { 
     return FinalClass.prototype.SubFunction.call(this); 
    }; 
} 

,你應該看到預期的繼承行爲。這是因爲在這種情況下FinalClass方法會改變通過'new'機制創建的上下文對象。您的原始方法是創建另一個不屬於FinalClass類型的對象。

+0

此前,我懷疑它可能與我從構造函數返回JSON類型對象的方式有關。不過,我已經放棄了這個想法,因爲很多其他在線樣本似乎都在使用它。我會給它一個鏡頭,看看會發生什麼!謝謝! – 2010-08-09 00:27:19

+0

夥計,你是男人! :D這是問題! WOOT!謝謝!!!!! – 2010-08-09 00:31:45

+0

@Mike:是的,關於JavaScript繼承模型主題的在線示例代碼是一致的可怕和困惑。對於(很長時間!)討論,請參閱[這個問題](http://stackoverflow.com/questions/1595611/how-to-properly-create-a-custom-object-in-javascript)。 – bobince 2010-08-09 00:45:47