2009-05-31 97 views
8

我知道有很多類似的問題都是對這個很好的答案。我試圖看看經典的繼承方法,或者那些閉包方法等。不知何故,我認爲它們對我來說或多或少是「黑客」方法,因爲它實際上並不是JavaScript所設計的。 (歡迎有人糾正我,如果我錯了)。 OK,只要它的作品,我滿足與像經典的遺傳模式:JavaScript的繼承

PARENTClass = function (basevar) { do something here; }; 
PARENTClass.prototype = { a: b, c: d}; // prototype is auto gen 

// Inheritance goes here 
CHILDClass = function (childvar) { do something; }; 
CHILDClass.prototype = new PARENTClass(*1); // Actual inheritance to the prototype statement 
// Instance 
CHILDInstance = new CHILDClass(whatever); 

以上是莫名其妙,我的理解JS的繼承。但是,我不知道如何實現的一個場景是,如果我想做一些初始化DURING對象創建(即在構造函數中),並且可以立即使用新對象......我對問題的示例可能不會太清楚,所以讓我用下面的C#的僞解釋什麼是我想要做的:(像初始化UI元素)

class PARENT { 
    public PARENT (basevar) { ... } 
} 
class CHILD : PARENT { 
    public CHILD (basevar) : PARENT (basevar) // constructor of child, and call parent constructor during construct. 
    { ... } 
} 

出於某種原因,他們將在構造函數中似乎做的最好辦法。任何人都有想法,我該怎麼做。 PS:在* 1中,我不知道我應該放在那裏。 PS2:上面的情況我DID找到了jquery.inherit庫可以做的,我只是想知道是不是用庫可以實現它。 PS3:或者我的理解錯誤。由於JavaScript不是爲了模仿OOP(這就是爲什麼我稱之爲破解),什麼是「正確」的邏輯來實現這一點。

+0

檢查了這一點:http://stackoverflow.com/questions/7486825/javascript-inheritance/12816953#12816953 – 2012-10-10 10:35:54

+0

使用的Object.create()繼承從基類的原型。通過這種方式,基類的變化會波及到子類,而不是相反。在我的博客上的更多詳細信息:http://ncombo.wordpress.com/2013/07/11/javascript-inheritance-done-right/ – Jon 2013-07-11 13:47:13

回答

17

它不是hack本身; JavaScript是一種原型的語言,如通過Wikipedia爲其中定義:

..classes不存在,和行爲重用(被稱爲基於類的語言繼承)通過克隆服務於現有的對象的過程中執行作爲原型。

正如它所說的,類不用於JavaScript;您創建的每個對象都來自JavaScript Object; JavaScript中的所有對象都有prototype對象,並且您創建的對象的所有實例都從其對象的原型對象中繼承了方法和屬性。請參閱MDC prototype對象參考以獲取更多信息。

由於這一點,當你調用行:

CHILDClass.prototype = new PARENTClass(); 

這使得CHILDClass對象從PARENTClass對象,它創建類似於繼承的想法添加效果的方法和屬性,將其原型對象以基於類的語言呈現。由於prototype對象會影響爲該對象創建的每個實例,因此這允許父對象的方法和屬性出現在子對象的每個實例中。

如果你想打電話給你的父類的構造函數在子類的構造函數,您使用JavaScript call功能;這允許您在子類的構造函數的上下文中調用父類的構造函數,因此將您的子類中的新原型屬性設置爲它們在父類中設置的屬性。

您也不需要在指定*1的位置放置任何內容,因爲該行僅用於將方法和屬性添加到子類的原型對象;但是,請記住它調用父類的構造函數,因此如果在父類構造函數的操作中有任何基本參數,則應檢查它們是否存在以避免發生JavaScript錯誤。

10

您可以手動在調用子類構造函數這樣的父類的構造:

CHILDClass = function (basevar) { 
    PARENTClass.call(this, basevar); 
    // do something; 
}; 

這裏的技巧是使用call方法,它可以讓你在不同對象的情況下調用一個方法。有關更多詳細信息,請參見the documentation of call

+0

我已搜索遍佈此功能。我從來沒有見過這麼簡單。我的問題是,這是一種「可接受的」方式嗎?如在,這會被視爲黑客?此外,這是目前,如`__proto__`不棄用? – 2014-08-27 17:09:24

1

JavaScript有沒有內置用於繼承層次支持類型擴展名應該是通過聚合進行,即直接加入期望的功能對象本身或它的原型,如果該屬性將被實例之間共享。

然而,JS是強大到足以使實施其他形式的對象構造的可能,包括經典的繼承。

給定一個clone function - 這足以補充「真」原型繼承,而不是JavaScript的私生子方法 - 你exampe可以這樣實現:

function ParentClass(baseVar) { 
    // do stuff 
} 

// don't overwrite the prototype object if you want to keep `constructor` 
// see http://joost.zeekat.nl/constructors-considered-mildly-confusing.html 
ParentClass.prototype.a = 'b'; 
ParentClass.prototype.c = 'd'; 

function ChildClass(childVar) { 
    // call the super constructor 
    ParentClass.call(this, childVar); 
} 

// don't inherit from a ParentClass instance, but the actual prototype 
ChildClass.prototype = clone(ParentClass.prototype); 
ChildClass.prototype.e = 'f'; 

它也可以添加一些語法糖類基於繼承 - 我自己的實現can be found here

從上面的例子將隨後讀

var ParentClass = Class.extend({ 
    constructor: function(baseVar) { 
     // do stuff 
    }, 
    a: 'b', 
    c: 'd' 
}); 

var ChildClass = ParentClass.extend({ 
    e: 'f' 
}); 
1

我有一個輕量級的JavaScript OOP的包裝,提供「類像」繼承,您可以覆蓋基礎的方法或調用基構造函數或成員。

您定義的類是這樣的:

//Define the 'Cat' class 
function Cat(catType, firstName, lastName) 
{ 
    //Call the 'Animal' constructor. 
    Cat.$baseNew.call(this, firstName, lastName); 

    this.catType = catType; 
} 
//Extend Animal, and Register the 'Cat' type. 
Cat.extend(Animal, { type: 'Cat' }, { 
    hello: function(text) 
    { 
     return "meaoow: " + text; 
    }, 
    getFullName: function() 
    { 
     //Call the base 'Animal' getFullName method. 
     return this.catType + ": " + Cat.$base.getFullName.call(this); 
    } 
}) 

//It has a built-in type system that lets you do stuff like: 

var cat = new Cat("ginger", "kitty", "kat"); 
Cat.getType()      // "Cat" 
cat.getBaseTypesAndSelf()   // ["Cat","Animal","Class"] 
cat.getType()      // "Cat" 
cat.isTypeOf(Animal.getType()) // "True" 

var dynamicCat = Class.createNew("Cat", ["tab","fat","cat"]) 
dynamicCat.getBaseTypesAndSelf() // ["Cat","Animal","Class"] 
dynamicCat.getFullName()   // tab: fat cat 

源代碼,請訪問:Class.js

我也有更多的細節在我的博客文章OOP in javascript

1

只是想我會提一些與傳統模式的問題,你會爲:

  1. 超類的引用變量將作爲所有實例的基本靜態變量提供。例如,如果super中有var arr = [1,2,3],並且執行instance_1.arr.push(4)instance_2.arr.push(5),所有這些實例都將「看到」所做的更改。
  2. 所以你解決1.艾曼的解決方案,Zakas稱之爲「偷構造」,但現在你調用構造函數兩次:一次爲原型,一次用於構造偷竊。解決方案 - 爲您的原型使用像inheritPrototype一個幫手(我發現整個執行本在這篇文章:inheritPrototype method FWIW,這基本上是從Zakas的書的第181頁和一些Crockford的研究組合來了。

  3. 無隱私(但話又說回來,你需要使用像持久對象模式的東西拿到這一點,這可能不是你想要的)

  4. 對象定義左「懸空」:解決方案 - 把一個if語句檢查你的任何原型的函數,然後用原型文字定義原型。

我在github上運行所有這些示例!

對我來說,真正理解這兩者同樣重要:Zakas和Crockford關於對象創建和繼承的書籍。我還需要嘗試一些不同的JavaScript TDD框架。所以我決定在TDD框架和JavaScript對象創建&繼承上創建一篇文章。它有運行代碼和jspec測試!這裏的鏈接:* My GitHub Open Source Essay/Book