zoukankan      html  css  js  c++  java
  • Effective JavaScript Item 38 调用父类的构造函数在子类的构造函数

    作为这一系列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);
    

    假设SpaceShipprototype对象是通过调用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对象以避免调用父类的构造函数。

  • 相关阅读:
    Linux curl命令添加参数
    postman无限循环执行接口用例
    xshell用root用户登录ubuntu
    centos5 yum源配置
    移动端布局方案
    vue + store2实现未提交信息自动保存
    sublime text里的terminal
    20180204
    2018.1.3 interview
    http协议
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/4560264.html
Copyright © 2011-2022 走看看