javaScript中的继承机制
javaScript的OOP概念会让人觉得它的OOP并不是真正的OOP,尤其是一开始接触学习C++的人更有这种感觉。确实,首先javaScript的对象模型和函数的表达方式是一样的,都是使用function关键字定义,而且按照javaScript的说法,函数也是一个Object,也许让人有点迷惑,但这也是javaScript的特点,不然它作为一种脚本语言的特性又从哪里体现呢。
javaScript的继承实现说起来有点烦,因为你得比较“刻意”地告诉别人,当前数据模型是从哪个对象继承过来的。
创建一个对象模型
首先创建一个新的对象模型Ball
,同时在这里也将具体讨论一下封装过程注意的问题,如下:
function Ball(x, y, velX, velY, color, size) {
this.x = x;
this.y = y;
this.velX = velX;
this.velY = velY;
this.color = color;
this.size = size;
Ball.prototype.draw = function() {
// blahblah...
}
Ball.prototype.update = function() {
// blahblah...
}
Ball.prototype.collisionDetect = function() {
// blahblah...
}
}
当我们创建一个新的Ball实例时,它的prototype和特性显示如下:
通过将函数的内部方法封装到prototype中是有原因的,因为本质上prototype属性是一个指向一个普通的Object对象的指针,包括Ball对象模型实例也有一个prototype属性指向这个对象,也就是说这个Object对象是被所有Ball实例共享的,那么根据OOP的原则,显然Ball的内部函数应当封装在prototype中,如果说Ball的函数你考虑像初始化普通变量一样,比如:
function Ball2(x, y) {
this.x = x;
this.y = y;
this.func = function() {
// blahblah...
}
}
当然是可以的,但有个问题便是每当创建一个新的实例,那么所有像func
这样被初始化的函数也将被新建一个实例,从设计的角度来看这是错的,假如对Ball2本身进行函数更新那么就反应不到实例上,从资源利用角度看也很浪费。
定义一个继承自Ball的子类Test
首先需要做的是创建一个子类的构造函数,因为要继承自父类的特性那么需要在沟构造函数中加入:
Ball.create(this, [parameters]);
function Test(x, y, velX, velY, color, size) {
Ball.create(this, x, y, velX, velY, color, size);
this.name = "Test";
}
看起来好像没有问题了,但其实情况是,当我们创建一个Test的实例后,该实例并不能调用Ball中的方法:
var test = new Test(1, 1, 1, 1, 'blue', 1);
// cannot find such function in Ball or Test
test.draw();
要知道javaScript的继承其实是通过prototype来实现的,那么显然我们的Test对象模型的prototype不是我们想要的,那么显然需要进行重新指定:
Test.prototype = Object.create(Ball.prototype)
新的实例会显示:
很奇怪,名称不对,那是因为目前使用的构造函数变成Ball的了,那么最后一步便是修改原型的构造函数:
Test.prototype.constructor = Test
那么最终显示:
总结
根据以上分析,javaScript的继承实现可以写成:
function Child(parentParams, ownParams) {
Parent.call(this, parentParams);
this.ownParams = ownParams;
Child.prototype = Object.create(Parent.prototype);
Child.prototype.construct = Child;
// Add more prototype functions
Child.prototype.func = function() {
// blahblah...
}
}