新年第一篇,再来闲谈继承。
上一次说了几个属性,继承主要用的还是原型。在形式上,有多种实现,但是在实际上会有各种差异。
有些看起来是像继承的,只是通过一种捷径实现了继承的方式,但是那并不是继承,所以在这里只列取在原型上拓展即可以食用的原型继承。
检验一个是否是真的继承,首先判断一下是否可以在原型上拓展,也就是new 对象之后,是不是在父类原型上的改变直接影响到子类上的原型内容,如果不满足这一点,就不属于继承范畴。使用 instanceof 比较
首先建立父类
function Parent(name){
this.name = name;
this.give = function(){ console.log(this.name + ' give')}
}
Parent.prototype.handup = function(){
console.log(this.name + 'hand up ');
}
建立好了父类。如何实现子类的继承关系。
1. 常规原型继承
使用prototype继承
function Child(name){
this.name = name;
}
Child.prototype = new Parent('Joy');
Child.prototype.constructor = Child; // 修正prototype的指向
var child = new Child('Tom');
这样继承来的对象上
child instanceof Parent ; // true
通过对原型链的改变,实现继承。
这种继承方式的好处就是单纯的继承。写起来类似接口一样,只有共有内容,没有私有属性。因为,所有的内容都是通过prototype取值,这一种继承总体来说算是最常规继承。
这种继承的几点缺陷
- 单继承
- 无法直接调用父类的构造函数。
在js中继承使用其实是非常少的,并且对于多继承来说就更少了,可以说忽略不计。
我看到还有一种寄生组合,说是因为调用了两遍父类构造函数。
function Parent(name){
this.name = name;
this.give = function(){ console.log(this.name + ' give') }
}
function Child(name){
Parent.call(this);
this.name = name;
}
(function(){
var supers = function(){}
supers.prototype = Parent.prototype;
Child.prototype = new supers;
})();
首先,父类自身的属性和函数,属于私有范畴,并不需要继承,这里用call破坏了原有的属性值。
其次,使用自执行函数,将父类的prototype转嫁到新的对象上去,减少了一次父类的调用,但是实际上并没有减少两次new的过程,并且原型上的new只有一次,所以说调用父类两次的并不成立。
因此:不建议这种方式。因为它属于画蛇添足的方式。
Child.prototype.constructor
这句话是重新修整constructor的指向。不修正时constructor指向的是原型类也就是Parent。但是如果new child.constructor()
重新 new一个该对象时,需要正确指向它的构造函数。
2. 其他继承实现方式
很抱歉,暂时没找着