假设,我们有个这样的需求:
两个种族,每个种族都有 名字、血量(默认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 中最常用的继承模式!
四、原型式继承
五、寄生式继承
六、寄生组合式继承
原文:http://www.cnblogs.com/linjilei/p/5122867.html