Javascript多重继承

时间:2011-09-10 18:11:51

标签: javascript inheritance

任何人都可以帮助您使用以下代码。我试图理解多重继承不确定为什么它不起作用。 BTW如果是多重继承的代码。谢谢

<!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>

7 个答案:

答案 0 :(得分: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

答案 1 :(得分:6)

你在“alertZ()”的调用中错误拼写了“abjz”。

经过更正,代码工作正常,据我所知(两个警报显示,一个用于Z,一个用于X)。

答案 2 :(得分:1)

您的代码不会导致classZ继承classX和classY,它只会复制其属性/方法。

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,classY和classZ继承而没有链,即

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

不幸的是,JS原型链系统不允许这样做,并且多重继承的灵活优势被有序原型链所扼杀。例如,如果您还希望实例cdef仅从classZ和classX继承: -

cdef --> classZ --> classX

然后在JS中,classZ原型必须从classY更改为classX并且会混淆abjz实例。而在多重继承中: -

cdef --> classZ
cdef --> classX

classZ仍然很好,因为没有尴尬的链条来处理。

答案 3 :(得分:1)

您可以通过在多继承树中的所有链中创建代理(总共)来创建代理,然后展平此树并将预先排序的所有这些代理原型链接起来DFS遍历。然后,您必须在继承树中的每个构造函数上更新[Symbol.hasInstance],以表明此构造函数确实具有此实例。我在这里工作:https://github.com/dosaygo-coder-0/postjs/blob/master/posttypes/src/mixOf.js

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

答案 4 :(得分:0)

JavaScript无法直接访问多重继承。

要使用它,您可以使用允许多重继承的类系统,如Ring.js

答案 5 :(得分:0)

答案 6 :(得分:0)

在Basarat Syed的Beginning Node.js一书中,他展示了一种继承模式。此代码演示了他设置原型链的方法。它使用util模块作为链接原型链的帮助器。

从第91页开始,“Javascript支持原型继承。他的书的第2章解释了原型是如何工作的。在JavaScript中,会查找当前项目的成员(例如item.foo),然后是其原型(item。 proto .foo),然后是原型的原型(item。 proto proto .foo),依此类推,直到原型本身(例如,item。 proto proto proto )为空。“ - Basarat Syed

注意:堆栈溢出编辑器从proto。

中删除了“__”前缀和后缀

示例代码。基类是Animal,Bird类派生自Animal,而超人类派生自Bird。

var inherits = require('util').inherits;

// Animal class, the parent
function Animal(name){
    this.name = name;

    // Additional initialization code
}

Animal.prototype.walk = function(destination){
    console.log(this.name,'is walking to',destination);
}

Animal.prototype.eat = function(food){
    console.log(this.name,'is eating',food);
}

// Bird class, child of Animal
function Bird(name){
    // call the Animal constructor
    Animal.call(this,name);

    // Additional initialization code
}

Bird.prototype.fly = function(destination){
    console.log(this.name,'is flying to',destination);
}

// Setup the prototype chain from child Bird to parent Animal
inherits(Bird,Animal);

// Superman class, child of Bird
function Superman(name){
    // Call the Bird constructor
    Bird.call(this,name);

    // Additional initialization code
}

Superman.prototype.jump = function(destination){
    console.log(this.name,'jumped over a',destination);
}

// Setup the prototype chain from child Superman to parent Bird
inherits(Superman,Bird);

// Create the parent instance
var animal = new Animal('elephant');
animal.walk('melbourne');
animal.eat('grass');

// Create the child of animal instance
var bird = new Bird('sparrow');
bird.walk('sydney');
bird.fly('melbourne');
bird.eat('seeds');

// Create the child of bird instance
var superman = new Superman('Clark Kent');
superman.fly('Gotham');
superman.walk('Daily planet');
superman.jump('Building');
superman.eat('Hot dogs');

输出:

大象正走向墨尔本 大象正在吃草 麻雀正走向悉尼 麻雀飞向墨尔本 麻雀正在吃种子 克拉克肯特飞往哥谭 克拉克肯特走到每日星球上 克拉克肯特跳过一幢建筑物 克拉克肯特正在吃热狗