2011-09-10 113 views
5

任何人都可以請幫助下面的代碼。我想了解多重繼承不知道爲什麼它不工作。順便說一句,如果代碼爲多重繼承。謝謝Javascript多繼承

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> 
<head> 
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> 

    <title>Test Doc</title> 
    <script type="text/javascript"> 
    function classX(){ 
     this.messageX="this is X Message"; 
     this.alertX=function(){ 
      alert(this.messageX); 
     }; 
    } 
    function classY(){ 
     this.messageY="this is Y Message"; 
     this.alertY=function(){ 
      alert(this.messageY); 
     }; 
    } 
    function classZ(){ 
     classX.apply(this); 
     classY.apply(this); 
     this.messageZ="this is Z Message"; 
     this.alertZ=function(){ 
      alert(this.messageZ); 
     }; 
    } 
    var abjz=new classZ(); 
    objz.alertZ(); 
    abjz.alertX(); 
    </script> 
</head> 

<body> 


</body> 
</html> 
+0

我可能完全脫離了這裏的基礎,但是你不會想申請'arguments'而不是'this'嗎? (或者甚至可以使用'call'而不是'apply') –

+4

他/她想讓「classX」和「classY」函數在與「classZ」構造函數中的新對象相同的上下文中操作。 「apply()」的第一個參數是要使用的上下文對象('this'值)。 – Pointy

+0

我爲此編寫了一個模塊,可以從npm https://npmjs.org/package/nmix或github https://github.com/topcloudsystems/nmix下載它。如果你想了解它背後的基本原理的更多信息,請查看我的博客:http://ncombo.wordpress.com/2012/12/29/javascript-multiple-inheritance/ – Jon

回答

6

在調用「alertZ()」時拼寫錯誤「abjz」。

經過糾正,代碼工作正常,據我所知(兩個警報顯示,一個用於Z和一個用於X)。

+0

我做了這個改變,但仍然z警報只是出現。我是否使用 – user443946

+0

正確應用? – user443946

+2

[這裏是jsfiddle。](http://jsfiddle.net/Pointy/eyNPr/)它對我來說工作正常。 – Pointy

16

JavaSript沒有真正的多重繼承。您只能從一個原型繼承,然後複製所需的其他屬性。您可以使用instanceof運算符對此進行測試。

修正拼寫錯誤後,您的演示程序有效,但實際上,您並非真正的繼承。要做到真正的JS繼承:

function A(){} 
function B(){} 
B.prototype = new A; 
b = new B; 
console.log(b instanceof A, b instanceof B); 
//-> true, true 

See also

更多JS inheriance on MDN

準多重繼承

function ctorX() { 
    this.messageX = "this is X Message"; 
    this.alertX = function() { 
     console.log(this.messageX); 
    }; 
} 

function ctorY() { 
    this.messageY = "this is Y Message"; 
    this.alertY = function() { 
     console.log(this.messageY); 
    }; 
} 

function ctorZ() { 
    ctorX.call(this); // This is the quasi-multiple inheritance 
    this.messageZ = "this is Z Message"; 
    this.alertZ = function() { 
     console.log(this.messageZ); 
    }; 
} 
ctorZ.prototype = new ctorY; // This is the actual inheritance 

var objz = new ctorZ(); 
objz.alertZ(); 
objz.alertY(); 
objz.alertX(); 

console.assert(objz instanceof ctorZ, 'objz is not instance of ctorZ'); 
console.assert(objz instanceof ctorY, 'objz is not instance of ctorY'); 
console.assert(objz instanceof ctorX, 'objz is not instance of ctorX'); 
//The last assert will fail since there is no true multiple inheritance 

Demo of Quasi-Multiple Inheritance

避免調用超級構造函數

HMR提出了一些觀點,即在某些情況下,用戶想要從特定的構造函數繼承,但超級構造函數需要參數並且不會失敗。繞過這個問題的方法是創建一個代理構造函數:

function C(x){if(!x) throw new Error;} 
function D(){} 
function proxyCtor(){/*should be noop*/} 
proxyCtor.prototype = C.prototype; 
D.prototype = new proxyCtor; 

var d = new D; 
console.assert(d instanceof C, 'c is not instance of D'); 
// will err if incorrect, which it's not 

Demo

+0

對不起,在'log'中兩次同樣的事情有什麼意義呢? – pimvdb

+0

請不要宣傳'Subclass.prototype = new Class();'模式。這是醜陋和低效率。 – ZenMaster

+7

這是'instanceof'運算符工作的唯一方法。在這種情況下,如果整個觀點要具有真正的繼承性,則任何低效率都可以忽略不計。另外,請不要在描述JavaScript構造函數時促進單詞_Class_的使用。 – kzh

1

您的代碼不被classZ引起classX和優雅的繼承,它只是在它們的屬性/方法的副本。

Object.getOwnPropertyNames(abjz) 

顯示: -

messageX,alertX,messageY,alertY,messageZ,alertZ 

但對於繼承你想要的警報方法來只停留在各自的班級,這樣對它們的更改將在稍後abjz反映。此外,如果您創建更多實例(如abjz),則不會出現方法維護問題。

你可以這樣做: -

var classX = {} 
classX.messageX = "this is X Message" 
classX.alertX = function(){ 
    alert(this.messageX) 
} 

var classY = Object.create(classX) 
classY.messageY = "this is Y Message" 
classY.alertY = function(){ 
    alert(this.messageY) 
} 

var classZ = Object.create(classY) 
classZ.messageZ = "this is Z Message" 
classZ.alertZ = function(){ 
    alert(this.messageZ) 
} 

var abjz = Object.create(classZ) 

這相當於: -

function classX(){} 
classX.prototype.messageX = "this is X Message" 
classX.prototype.alertX = function(){ 
    alert(this.messageX) 
} 

function classY(){} 
classY.prototype = classX.prototype 
classY.prototype.messageY = "this is Y Message" 
classY.prototype.alertY = function(){ 
    alert(this.messageY) 
} 

function classZ(){} 
classZ.prototype = classY.prototype 
classZ.prototype.messageZ = "this is Z Message" 
classZ.prototype.alertZ = function(){ 
    alert(this.messageZ) 
} 

var abjz = new classZ() 

兩者都應該輸出: -

alert(Object.getOwnPropertyNames(abjz)) // 
abjz.alertX()        // this is X Message 
abjz.alertY()        // this is Y Message 
abjz.alertZ()        // this is Z Message 

所以現在abjz從classZ它繼承繼承從classY繼承自線性原型鏈中的classX,如下所示: -

abjz --> classZ --> classY --> classX 

雖然這不是多重繼承。要獲得,abjz需要從每個classX,優雅和classZ的無鏈直接繼承,即

abjz --> classZ 
abjz --> classY 
abjz --> classX 

不幸的是,JS原型鏈系統不允許這樣,和多重繼承的彈性福利都死光了通過有序的原型鏈。例如,如果你也想一個實例CDEF剛剛從classZ和classX繼承: -

cdef --> classZ --> classX 

然後在JS的classZ原型必須從優雅改爲classX和攪亂abjz實例。而在多重繼承中: -

cdef --> classZ 
cdef --> classX 

classZ仍然很好,因爲沒有尷尬的鏈條來處理。

+1

您的前兩個大代碼塊不相同。 'var classX = {}; classX.messageX =「this is X Message」;'不等於'function classX(){}; classX.prototype.messageX =「這是X消息」。第一個是創建一個包含屬性的單個對象,第二個創建一個帶有原型屬性的(假定的)對象構造函數。其次,'classY.prototype = classX.prototype'不會正常工作。他們可能會以類似的方式開始工作,但如果在運行時發生任何更改,事情將會開始中斷對我來說已經很晚了,所以我冒着對這一切完全錯誤的風險。 :)〜 – kalisjoshua

+0

@kalisjoshua我認爲你是對的。在後面的塊中,'classX.prototype.messageX =「這是X消息」'實際上是'classX.prototype = {messageX:「這是X消息」}'。不同之處在於屬性'.messageX'不再是'classX'的屬性,因爲它已經在前面的塊中。在後面的塊中,messageX是已被設置爲對象'classX.prototype'的匿名創建的原型的一個屬性。因爲原型鏈和繼承在這裏很重要,所以它不是很精確(可以說錯了),說這些塊是等價的。 – humanityANDpeace

0

JavaScript不允許訪問開箱即用的多重繼承。

要使用它,您可以使用允許多重繼承的類系統,如Ring.js

1

您可以通過創建圍繞在多重繼承樹中的所有連鎖店的原型代理做(總共)然後展開此樹,並在預定義的DFS遍歷中鏈接所有這些代理原型。然後,您必須更新繼承樹中每個構造函數的[Symbol.hasInstance],以表示此構造函數確實具有此實例。我正在這裏工作:https://github.com/dosaygo-coder-0/postjs/blob/master/posttypes/src/mixOf.js

目前(2016年10月12日),上述想法尚未完全實施。