2011-10-27 41 views
0

也許我這樣做不對。我想設置一個基類和兩個從該類繼承的類。但是,它告訴我,一個孩子是另一個孩子的一個例子......這不可能是正確的,可以嗎?我在這裏做錯了什麼?爲什麼是典型的繼承子類另一個孩子的類的實例?

function BaseClass(){} 
function Child1(){} 

Child1.prototype = BaseClass.prototype; 
Child1.prototype.constructor = Child1; 

function Child2(){} 
Child2.prototype = BaseClass.prototype; 
Child2.prototype.constructor = Child2; 

console.log((new Child1() instanceof Child2)); // true 
+0

這裏是在JS使用繼承的許多方面是一個很好的資源:HTTP:/ /www.3site.eu/doc/ –

回答

2

Child1.prototype = BaseClass.prototype;

應該Child1.prototype = Object.create(BaseClass.prototype)

你不想原型對象是相同的,你想要一個新的原型對象,從BaseClass

繼承

Live Example

免責聲明:Object.create是ES5,使用ES5-shim遺留平臺的支持。

爲了讓您更全面的例子:

// Create base prototype 
var Base = { 
    method: function() { 
    return this.things; 
    }, 
    constructor: function (things) { 
    this.things = things; 
    } 
}; 
// Link constructor and prototype 
Base.constructor.prototype = Base; 

// Create child prototype that inherits from Base 
var Child = Object.create(Base); 
// overwrite constructor 
Child.constructor = function (things) { 
    things++; 
    Base.constructor.call(things); 
} 
// Link constructor and prototype 
Child.constructor.prototype = Child; 

// Swap prototype and constructor around to support new 
ChildFactory = Child.constructor; 

var c = new ChildFactory(41); 
console.log(c.method()); // 42 

視覺:

var Base = { ... }

在這裏,我們簡單地創建方法和屬性的對象。我們希望能夠創建此對象的實例。所以Base是一個「類」和所有它的方法和屬性可以從實例(包括constructor)進行訪問。

Base.constructor.prototype = Base;

您需要關聯的「構造函數」,這是你可以用new調用一個函數,它會給你的對象ConstructorFunction.prototype的新實例一起與原型對象。這基本上是一些你需要手動完成的粘合劑,因爲ES不會爲你做這件事。

如果您忘了這麼做,那麼構造函數(即X.constructor)沒有.prototype屬性來使實例繼承。

var Child = Object.create(Base);

創建一個新的對象,其[[Prototype]]Base。這基本上是你的原型鏈

Child -> ([[Prototype]] = Base) -> ([[Prototype]] = Object.prototype) -> null 

Child.x = ...

現在我們添加這是兒童的方法實例將繼承屬性,我們的子對象的開始。基本上我們正在創建一個新的原型對象來繼承。所有實例都將共享這些方法,並在原型鏈上共享方法(包括Base)。

ChildFactory = Child.constructor;

new關鍵字只能在構造函數,而不是原型對象,因此,我們需要從根本上說,建立「類時,「我們的原型對象變量切換到構造函數變量」

個人「我發現原型對象非常令人愉快,可以直接處理,並且在創建實例時我發現構造函數很適合處理。

現在,當我們調用var c = new Child(41);

它將調用我們定義的構造函數,這將增加things,然後調用基構造函數。

注意此時C的原型鏈看起來像

c -> ([[Prototype]] = Child) 
    -> ([[Prototype]] = Base) 
    -> ([[Prototype]] = Object.prototype) 
    -> null 
+0

謝謝!這就像一個魅力......我必須做更多的閱讀,看看幕後發生了什麼。網上有很多關於如何正確進行繼承的不同示例,並且它們似乎都有無參數的構造函數以避免難以理解的地方:) – Paul

3

您同時設置你的類完全相同的對象(「BaseClass.prototype」),並設置了「構造」的屬性就可以了,以「CHILD2」的原型。換句話說「Child1.prototype」和「Child2.prototype」是相同的,所以只有一個涉及您的代碼「構造」特性,以及它最終被「CHILD2」。

也許你想將這些原型設置爲實例的BaseClass?

Child1.prototype = new BaseClass(); 
Child1.prototype.constructor = Child1; 

Child2.prototype = new BaseClass(); // a different object 
Child2.prototype.constructor = Child2; 

(@Raynos指出實例原型值一樣,可能會引起微妙的問題,所以你可能更喜歡使用他的答案的做法。)

+0

你真的應該避免'.prototype = new X()'你不想將'.prototype'初始化爲X的一個實例,你只是想實例化。 (即不要調用構造函數!) – Raynos

+0

當你的基類構造函數有參數時會發生什麼 - 你需要在那裏和那裏初始化它們嗎?我真正的子類代碼調用了BaseClass.call(this,'argument1','argument2');在其構造函數中。 – Paul

+0

確定@Raynos是的,這可能是真的;我不會那麼經常處理這樣的問題:-)我會添加一個不是。 – Pointy

1

這並不意味着檢查對象new Child1()是否由「Child1」構造函數創建。 instanceof運營商只需要一個對象原型 - (new Child1()).[[Prototype]]並檢查其在原型鏈中的存在,並從「Child1.prototype」中檢查主題。運算符instanceof通過構造函數的內部[[HasInstance]]方法激活。 所以,你需要改變你的代碼以下列方式:

function BaseClass(){} 
function Child1(){} 

Child1.prototype = new BaseClass(); 
Child1.prototype.constructor = Child1; 

function Child2(){} 
Child2.prototype = new BaseClass(); 
Child2.prototype.constructor = Child2; 
console.log((new Child1() instanceof Child2)); // false 

這將是正確執行的OOP在JavaScript

相關問題