作为这一系列Effective JavaScript的读书笔记。

在一个游戏或者图形模拟的应用中。都会有场景(Scene)这一概念。在一个场景中会包括一个对象集合,这些对象被称为角色(Actor)。

而每一个角色依据其类型会有一个图像用来表示,同一时候场景也须要保存一个底层图形展示对象的引用,被称为上下文(Context):

function Scene(context, width, height, images) {
this.context = context;
this.width = width;
this.height = height;
this.images = images;
this.actors = [];
}
Scene.prototype.register = function(actor) {
this.actors.push(actor);
};
Scene.prototype.unregister = function(actor) {
var i = this.actors.indexOf(actor);
if (i >= 0) {
this.actors.splice(i, 1);
}
};
Scene.prototype.draw = function() {
this.context.clearRect(0, 0, this.width, this.height);
for (var a = this.actors, i = 0, n = a.length; i < n; i++) {
a[i].draw();
}
};

场景中全部的角色都继承自一个基类,这个基类用来抽象全部角色具有的属性和方法。比方,每一个角色对象都会保存它所在场景的引用,和坐标信息:

function Actor(scene, x, y) {
this.scene = scene;
this.x = x;
this.y = y;
scene.register(this);
}

相同地,在Actor类型的prototype对象上会定义公共的方法:

Actor.prototype.moveTo = function(x, y) {
this.x = x;
this.y = y;
this.scene.draw();
};
Actor.prototype.exit = function() {
this.scene.unregister(this);
this.scene.draw();
};
Actor.prototype.draw = function() {
var image = this.scene.images[this.type];
this.scene.context.drawImage(image, this.x, this.y);
};
Actor.prototype.width = function() {
return this.scene.images[this.type].width;
};
Actor.prototype.height = function() {
return this.scene.images[this.type].height;
};

有了角色基础类。就能够在其之上创建详细类型了。比方当创建一个宇宙飞船(SpaceShip)角色时,能够这样实现:

function SpaceShip(scene, x, y) {
Actor.call(this, scene, x, y);
this.points = 0;
}

为了让SpaceShip的实例也可以拥有全部角色应该有的属性,所以在SpaceShip的构造函数体内首先调用了父类(Actor)的构造函数,紧接着会初始化SpaceShip实例自身的属性,比方以上的points。

为了让SpaceShip类型确确实实地成为Actor类型的子类型,SpaceShip类型的prototype对象也必需要继承自Actor类型的prototype对象。这能够通过ES5提供的Object.create方法完毕(非ES5的实现方式能够參考Item
33):

SpaceShip.prototype = Object.create(Actor.prototype);

假设SpaceShip的prototype对象是通过调用Actor的构造函数来获得的,那么会出现一系列的问题:

SpaceShip.prototype = new Actor();

在调用Actor构造函数的时候,没法传入合理的參数。由于Actor接受场景对象和坐标信息作为參数,而SpaceShip类型的prototype对象的目的是为了容纳SpaceShip类型中一些公用的属性和方法。显然场景和坐标信息会随着SpaceShip实例的不同而不同。将这些信息放在prototype对象上是不合适的。

父类型的构造函数仅仅能在子类型的构造函数中被调用,而子类型的prototype对象是继承自父类型的prototype对象。

这一点在创建子类型的prototype时须要注意。

一旦完毕了子类型prototype对象的创建。就能够在其上设置公用的属性和方法了:

SpaceShip.prototype.type = "spaceShip";
SpaceShip.prototype.scorePoint = function() {
this.points++;
};
SpaceShip.prototype.left = function() {
this.moveTo(Math.max(this.x - 10, 0), this.y);
};
SpaceShip.prototype.right = function() {
var maxWidth = this.scene.width - this.width();
this.moveTo(Math.min(this.x + 10, maxWidth), this.y);
};

此时,Actor类型,SpaceShip类型以及它们的prototype对象之间的关系例如以下:

总结

  1. 在子类型的构造函数中调用父类型的构造函数,并显式传入this的指向。
  2. 使用Object.create方法创建亚型prototype对象以避免调用父类的构造函数。

Effective JavaScript Item 38 调用父类的构造函数在子类的构造函数的更多相关文章

  1. Effective JavaScript Item 21 使用apply方法调用函数以传入可变參数列表

    本系列作为Effective JavaScript的读书笔记. 以下是一个拥有可变參数列表的方法的典型样例: average(1, 2, 3); // 2 average(1); // 1 avera ...

  2. Effective JavaScript Item 37 认识this的隐式指向

    本系列作为Effective JavaScript的读书笔记. CSV数据通常都会被某种分隔符进行分隔.所以在实现CSV Reader时,须要支持不同的分隔符.那么,非常自然的一种实现就是将分隔符作为 ...

  3. Effective JavaScript Item 39 绝不要重用父类型中的属性名

    本系列作为Effective JavaScript的读书笔记. 假设须要向Item 38中的Actor对象加入一个ID信息: function Actor(scene, x, y) { this.sc ...

  4. Effective JavaScript Item 30 理解prototype, getPrototypeOf和__proto__的不同

    本系列作为Effective JavaScript的读书笔记. prototype,getPropertyOf和__proto__是三个用来訪问prototype的方法.它们的命名方式非常类似因此非常 ...

  5. Effective JavaScript Item 46 优先使用数组而不是Object类型来表示有顺序的集合

    本系列作为Effective JavaScript的读书笔记. ECMAScript标准并没有规定对JavaScript的Object类型中的属性的存储顺序. 可是在使用for..in循环对Objec ...

  6. Effective JavaScript Item 10 避免使用with

    本系列作为Effective JavaScript的读书笔记. Item 9:避免使用withkeyword 重点: 设计withkeyword本来是为了让代码变简洁,可是却起到了相反的效果.比方: ...

  7. Effective JavaScript Item 22 使用arguments来创建接受可变參数列表的函数

    本系列作为Effective JavaScript的读书笔记. 在Item 21中,介绍了结合apply方法实现的可变參数列表函数average,它实际上仅仅声明了一个数组作为參数,可是利用apply ...

  8. Effective JavaScript Item 31 优先使用Object.getPrototypeOf,而不是__proto__

    本系列作为Effective JavaScript的读书笔记. 在ES5中引入了Object.getPrototypeOf作为获取对象原型对象的标准API.可是在非常多运行环境中.也提供了一个特殊的_ ...

  9. Effective JavaScript Item 40 避免继承标准类型

    本系列作为Effective JavaScript的读书笔记. ECMAScript标准库不大.可是提供了一些重要的类型如Array,Function和Date.在一些场合下.你或许会考虑继承当中的某 ...

随机推荐

  1. Java 网络I/O模型

    网络I/O模型 人多了,就会有问题.web刚出现的时候,光顾的人很少.近年来网络应用规模逐渐扩大,应用的架构也需要随之改变.C10k的问题,让工程师们需要思考服务的性能与应用的并发能力. 网络应用需要 ...

  2. 解决Eclipse 启动后总是Building WorkSpace(sleeping)

    打开eclipse后eclipse总是在Building WorkSpace(sleeping),我的解决方案是,Project -> Building AutoMatically关闭就好了,以 ...

  3. [GraphQL] Create an Input Object Type for Complex Mutations

    When we have certain mutations that require more complex input parameters, we can leverage the Input ...

  4. 【机器学习实战】第7章 集成方法(随机森林和 AdaBoost)

    第7章 集成方法 ensemble method 集成方法: ensemble method(元算法: meta algorithm) 概述 概念:是对其他算法进行组合的一种形式. 通俗来说: 当做重 ...

  5. js实现md5加密sha1加密等

    1.base64加密 在页面中引入base64.js文件,调用方法为: <!DOCTYPE HTML> <html> <head> <meta charset ...

  6. LUA整合进MFC代码

    这几天研究了一下lua,主要关注的是lua和vc之间的整合,把代码都写好放在VC宿主程序里,然后在lua里调用宿主程序的这些代码(或者叫接口.组件,随便你怎么叫),希望能用脚本来控制主程序的行为.这实 ...

  7. React Native 开发环境安装和配置使用报错: -bash: react-native: command not found

    [React  Native 开发环境安装和配置:-bash: react-native: command not found 报错: 前提是安装homebrew,node.js ,npm ,watc ...

  8. Guava中TreeRangeMap基本使用

    RangeMap跟一般的Map一样.存储键值对,依照键来取值.不同于Map的是键的类型必须是Range,也既是一个区间.RangeMap在Guava中的定义是一个接口: public interfac ...

  9. php取两位小数的几种方法

    php取两位小数的几种方法 一.总结 一句话总结: 1.round   四舍五入 2.sprintf   c语言方式 3.number_format 千分位数字格式化的那个函数 二.php取两位小数的 ...

  10. git自己操作命令组集合

    git自己操作命令组集合 一.总结 一句话总结: 1.官方有非常详细的中文文档资料,任何组件或者插件记得看有没有文档资料,这个用起来快,配合百度. 2.git clone命令是直接把git仓库上面的代 ...