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

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

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

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


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

 function HumanWarrior(name) {
this.name = name ;
this.race = "Human" ;
this.profess = "Warrior" ;
this.health = 200 ;
this.action = ["attack","jump","movespeed"] ;
this.power = 110 ;
} function HumanMage(name) {
this.name = name ;
this.race = "Human" ;
this.profess = "Mage" ;
this.health = 200 ;
this.action = ["magic","jump","movespeed"] ;
this.mage = 165 ;
} function OrcWarrior(name) {
this.name = name ;
this.race = "Orc" ;
this.profess = "Warrior" ;
this.health = 220 ;
this.action = ["attack","jump","movespeed"] ;
this.power = 100 ;
} function OrcMage(name) {
this.name = name ;
this.race = "Orc" ;
this.profess = "Mage" ;
this.health = 220 ;
this.action = ["magic","jump","movespeed"] ;
this.mage = 150 ;
} var player1 = new HumanWarrior("Heroic") ;
var player2 = new HumanMage("Wizard") ;
var player3 = new OrcWarrior("Brave") ;
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 中最常用的继承模式!


四、原型式继承


五、寄生式继承


六、寄生组合式继承


JavaScript 对象 之继承对象 学习笔记的更多相关文章

  1. 《JavaScript DOM 编程艺术》 学习笔记

    目录 <JavaScript DOM 编程艺术> 学习笔记 第一章 js简史 第二章 js语法 准备工作 语法 第三章 DOM DOM中的D DOM中的O DOM中的M 第四章 js图片库 ...

  2. 【JavaScript】类继承(对象冒充)和原型继承__深入理解原型和原型链

    JavaScript里的继承方式在很多书上分了很多类型和实现方式,大体上就是两种:类继承(对象冒充)和原型继承. 类继承(对象冒充):在函数内部定义自身的属性的方法,子类继承时,用call或apply ...

  3. .NET 云原生架构师训练营(对象过程建模)--学习笔记

    目录 UML OPM OPM优化 UML 1997年发布UML标准 主要域 视图 图 主要概念 结构 静态视图 类图 类.关联.泛化.依赖关系.实现.接口 用例视图 用例图 用例.参与者.关联.扩展. ...

  4. Java中对象的比较(学习笔记)

    1)详细说明对象的比较方式有哪些? ①对象引用的比较("= ="运算符) "= ="是将对象的引用进行比较,实质是比较两个引用变量是否引用同一个对象.注意的点: ...

  5. JavaScript闭包(Closure)学习笔记

    闭包(closure)是JavaScript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 下面就是我的学习笔记,对于JavaScript初学者应该是很有用的. 一.变量的作用域 要理解 ...

  6. 《JavaScript DOM编程艺术》学习笔记(一)

    这本书是我听说学习前端基础入门书籍,于是就开始看了,大概是从5月10号开始看的吧,一直看到现在,差不多要看完了,书是挺厚的...286页,不过比起JAVASCRIPT权威指南来说还是差多了,权威指南才 ...

  7. JavaScript权威设计--JavaScript类型,值,变量(简要学习笔记三)

    1.负号是一元求反运算 如果直接给数字直接量前面添加负号可以得到他们的负值     2.JavaScript中的运算超出了最大能表示的值不会报错,会显示Infinity. 超出最小也不报错,会显示-I ...

  8. Javascript垃圾回收机制(学习笔记)

    1,javascript具有自动的垃圾回收机制,自动内存的分配和无用内存的回收都可以自动管理.垃圾回收器周期性的执行: 2,Javascript的垃圾回收策略分为:引用计数和标记清除: 2.1 标记清 ...

  9. JavaScript原型与原型链学习笔记

    一.什么是原型?原型是一个对象,其他对象可以通过它实现属性继承.简单的说就是任何一个对象都可以成为原型 prototype属性: 我们创建的每个函数都有一个prototype属性,这个属性是一个指针, ...

  10. JavaScript权威设计--CSS(简要学习笔记十六)

    1.Document的一些特殊属性 document.lastModified document.URL document.title document.referrer document.domai ...

随机推荐

  1. linux命令:ln

    1.命令介绍: nl用来显示文件的行号并打印出来. 2.命令格式: nl [选项] 文件 3.命令参数: -b  :指定行号指定的方式,主要有两种: -b a :表示不论是否为空行,也同样列出行号(类 ...

  2. javascript之小积累-.-typeof与instanceof的区别

    1.typeof 是获取一个变量或表达式的类型,返回的值通常是string, number, boolean, object(null, 数组, 对象), function, undefined,可以 ...

  3. Unity Sprite切割导出

    这次需要将美术提供的Sprite图集切割导出,整体思路依然和上次的Sprite转prefab一致,只是在转prefab的逻辑修改为了创建Texture的逻辑. 过程很简单,直接看最终代码结果: usi ...

  4. 线程和NSThread 、 NSOperation

    1 使用NSThread实现打地鼠 1.1 问题 NSThread是ios提供的轻量级的多线程解决方案,但是需要自己管理线程的生命周期.线程同步等.本案例使用NSThread实现一个打地鼠的小游戏,在 ...

  5. Java常量字符串String理解

    Java常量字符串String理解 以前关于String的理解仅限于三点:1.String 是final类,不可继承2.String 类比较字符串相等时时不能用“ == ”,只能用  "eq ...

  6. Python UDP broadcast PermissionError: [Errno 13] Permission denied

    /********************************************************************** * Python UDP broadcast Permi ...

  7. css模糊效果

    CSS代码: .blur { filter: url(blur.svg#blur); /* FireFox, Chrome, Opera */ -webkit-filter: blur(10px); ...

  8. Monte Carlo Approximations

    准备总结几篇关于 Markov Chain Monte Carlo 的笔记. 本系列笔记主要译自A Gentle Introduction to Markov Chain Monte Carlo (M ...

  9. html随记

    姓名输入框:<input type="text" value="默认有值"/> 密码输入框:<input type="text&qu ...

  10. linux与windows的不同

    linux 严格区分大小写:linux 所有内容都以文件形式保存,包括用户和硬件:linux 不以文件后缀名来区分文件类型:但有一些便于管理员区分文件类型的约定俗称的后缀:windows下的程序不能直 ...