假设,我们有个这样的需求:

  两个种族,每个种族都有 名字、血量(默认200)、行为(行为有 跳跃、移动速度 这些属性)等共有属性。

  人族能量值比兽人多10%,兽人血量比人族多10%。

  职业有战士和法师两个职业,战士和法师有不一样的能量条:战士的为 怒气值(默认100),法师的为法力值(默认150)。战士有个自带的技能,为 攻击,法师有个自带的技能,为魔法攻击。这两个都属于 行为的属性。


 

  因为我们已经学过对象的创建,我们可以很轻松的写下如下代码

 1 function HumanWarrior(name) {
 2     this.name = name ;
 3     this.race = "Human" ;
 4     this.profess = "Warrior" ;
 5     this.health = 200 ;
 6     this.action = ["attack","jump","movespeed"] ;
 7     this.power = 110 ;
 8 }
 9 
10 function HumanMage(name) {
11     this.name = name ;
12     this.race = "Human" ;
13     this.profess = "Mage" ;
14     this.health = 200 ;
15     this.action = ["magic","jump","movespeed"] ;
16     this.mage = 165 ;
17 }
18 
19 function OrcWarrior(name) {
20     this.name = name ;
21     this.race = "Orc" ;
22     this.profess = "Warrior" ;
23     this.health = 220 ;
24     this.action = ["attack","jump","movespeed"] ;
25     this.power = 100 ;
26 }
27 
28 function OrcMage(name) {
29     this.name = name ;
30     this.race = "Orc" ;
31     this.profess = "Mage" ;
32     this.health = 220 ;
33     this.action = ["magic","jump","movespeed"] ;
34     this.mage = 150 ;
35 }
36 
37 var player1 = new HumanWarrior("Heroic") ;
38 var player2 = new HumanMage("Wizard") ;
39 var player3 = new OrcWarrior("Brave") ;
40 var player4 = new OrcMage("Warlock") ;

  上面的代码,几乎给每个种族的每种职业都添加了构造函数,造成了很多的重复。所以我们试着给来个继承。


 一、原型链

   利用原型让一个引用类型继承另一个引用类型的属性和方法。

function Person() {
    this.health = 200 ;
    this.power = 100 ;
    this.action = ['jump','movespeed'] ;
}
// 初始化,给每个玩家初始化血量和技能。 Person.prototype.init
= function () { this.health = parseInt(this.health * this.healthtimes); this.power = parseInt(this.power * this.powertimes); if (this.profess === "Warrior") { this.action.push("attack"); }else { this.action.push("magic"); this.mage = this.power; this.power = null; } } function Human(name,profess) { this.name = name ; this.profess = profess; this.race = "Human" ; this.healthtimes = 1; this.powertimes = 1.1; } function Orc(name,profess) { this.name = name ; this.profess = profess; this.race = "Orc" ; this.healthtimes = 1.1; this.powertimes = 1; } Human.prototype = new Person(); Orc.prototype = new Person(); var player1 = new Human("Heroic","Warrior") ; var player2 = new Human("Wizard","Mage") ; var player3 = new Orc("Brave","Warrior") ; var player4 = new Orc("Warlock","Mage");
// 初始化
player1.init() ;
player2.init() ;
player3.init() ;
player4.init() ;

   这里有个很严重的问题。所有 Human的实例 和 Orc的实例 都会共享一个 action。 结果就是player1,player2 的 action 是一样的, player3,player4 的 action 也是一样的。这是原型链的一个缺陷,我们可以采用另一个方法去解决这个问题。


 

二、借用构造函数

  在子类型构造函数的内部调用超类型构造函数。

 

function Person(name) {
    this.name = name ;
    this.health = 200 ;
    this.power = 100 ;
    this.action = ["jump","movespeed"] ;
}
Person.prototype.init = function () {
    
}
function Warrior() {
    this.action.push("attack");
    this.health = parseInt(this.health * this.healthtimes);
    this.power = parseInt(this.power * this.powertimes);
}
function Mage() {
    this.action.push("Magic");
    this.health = parseInt(this.health * this.healthtimes);
    this.power = parseInt(this.power * this.powertimes);
    this.mage = this.power;
    this.power = null;
}
function Human(name,profess) {
    Person.call(this,name,profess) ;
    this.race = "Human" ;
    this.healthtimes = 1;
    this.powertimes = 1.1;
    if (profess == "Warrior") {
        Warrior.call(this);
    }else{
        Mage.call(this);
    }
}
function Orc(name,profess) {
    Person.call(this,name) ;
    this.profess = profess ;
    this.race = "Orc" ;
    this.healthtimes = 1.1;
    this.powertimes = 1;
    if (profess == "Warrior") {
        Warrior.call(this);
    }else{
        Mage.call(this);
    }
}

var player1 = new Human("Heroic","Warrior") ;
var player2 = new Human("Wizard","Mage") ;
var player3 = new Orc("Brave","Warrior") ;
var player4 = new Orc("Warlock","Mage") ;

//    错误 无法初始化,无法调用原型的方法了。
//    player1.init() ;

  该方法确实让 每个玩家都拥有了属于自己的 action,但是依然出现了另一种问题。那就是 没办法调用 Person() 的方法了,只能在子类上另写方法了,谈不上方法的复用了。


 

三、组合继承(伪经典继承)

  集 原型链 和 借用构造函数 的技术组合成一块,发挥二者之长的一种继承模式。

function Person(name) {
    this.name = name ;
    this.health = 200 ;
    this.power = 100 ;
    this.action = ["jump","movespeed"] ;
}
Person.prototype.show = function () {
    var s = "name:" + this.name + "; Health:" + this.health + "; action:" + this.action.join(",");
    alert(s);
} 
function Warrior() {
    this.action.push("attack");
    this.health = parseInt(this.health * this.healthtimes);
    this.power = parseInt(this.power * this.powertimes);
}
function Mage() {
    this.action.push("Magic");
    this.health = parseInt(this.health * this.healthtimes);
    this.power = parseInt(this.power * this.powertimes);
    this.mage = this.power;
    this.power = null;
}
function Human(name,profess) {
    //继承属性
    Person.call(this,name,profess) ;
    this.race = "Human" ;
    this.healthtimes = 1;
    this.powertimes = 1.1;
    if (profess == "Warrior") {
        //继承属性
        Warrior.call(this);
    }else{
        //继承属性
        Mage.call(this);
    }
}
function Orc(name,profess) {
    //继承属性
    Person.call(this,name) ;
    this.profess = profess ;
    this.race = "Orc" ;
    this.healthtimes = 1.1;
    this.powertimes = 1;
    if (profess == "Warrior") {
        //继承属性
        Warrior.call(this);
    }else{
        //继承属性
        Mage.call(this);
    }
}
//继承方法
Human.prototype = new Person();
Orc.prototype = new Person();

var player1 = new Human("Heroic","Warrior") ;
var player2 = new Human("Wizard","Mage") ;
var player3 = new Orc("Brave","Warrior") ;
var player4 = new Orc("Warlock","Mage") ;

  非常完美!无论是属性还是方法,都已经完美的继承了他们的父类。

  组合继承 避免了 原型链 和 构造函数 的缺陷,又融合了他们的优点,成为 JavaScript 中最常用的继承模式!


 

四、原型式继承


 

五、寄生式继承


 

六、寄生组合式继承


 

posted on 2016-01-13 22:41  小玥光  阅读(165)  评论(0编辑  收藏  举报