一.类式继承
//父类
function superClass(value){
this.superValue = value;
}
superClass.prototype.getSuperValue = function(){
return this.superValue;
}
//子类
function subClass(value){
this.subValue = value;
}
//子类继承父类
subClass.prototype = new superClass('super');
subClass.prototype.getSubValue = function(){
return this.subValue;
}
var instance = new subClass('sub');
console.log(instance.getSuperValue());//super
类式继承有两个明显的缺点:
1.父类中的公有属性要是引用类型,就会在子类中被所有实例共用,如果其中一个子类实例更改了父类的公有属性则会引响到其他实例。
2.在实例化子类的时候无法通过传参来对弗雷构造函数内的属性进行初始化。
二.构造函数继承
// 构造函数继承
function superClass(id){
this.books = ['html', 'css', 'js'];
this.id = id;
}
superClass.prototype.showBooks = function(){
console.log(this.books);
}
function subClass(id){
superClass.call(this, id);
}
var instance1 = new subClass(100);
var instance2 = new subClass(200);
instance1.books.push('php');
console.log(instance1.books);//[ 'html', 'css', 'js', 'php' ]
console.log(instance2.books);//[ 'html', 'css', 'js']
console.log(instance1.showBooks);//undefined
可以看到,构造函数继承是在子类构造函数中调用父类构造函数,这样解决了类式继承中出现的两个问题,但同时又增加了一个新的问题那就是子类实例无法共享父类原型中的属性和方法。如果想要继承必须放在父类构造函数中,这样会造成大量的内存浪费,不符合代码复用原则。
三.组合继承
function superClass(id){
this.books = ['html', 'css', 'js'];
this.id = id;
}
superClass.prototype.showBooks = function(){
console.log(this.books);
}
function subClass(id, name){
superClass.call(this, id);
this.name = name;
}
subClass.prototype = new superClass();
var instance1 = new subClass(100, 'jack');
var instance2 = new subClass(200, 'tom');
instance1.books.push('php');
console.log(instance1.books);// ['html', 'css', 'js', 'php']
console.log(instance2.books);// ['html', 'css', 'js']
console.log(instance1.showBooks());// ['html', 'css', 'js', 'php']
可以看到组合继承是结合了类式继承和构造函数继承的优点,但还是存在一点小瑕疵那就是父类构造函数被执行了两遍,这多少让人觉得有点不太舒服。
四.原型式继承
function inheritObject(o){
// 声明一个过渡对象
function F(){};
F.prototype = o;
return new F();
}
这其实就是对于类式继承的一个封装,也是Object.create()方法的原型,当然类式继承中存在的问题这里依然会存在。
五.寄生式继承
function createBook(obj){
var o = new inheritObject(obj);
o.getName = function(){
console.log(name);
}
return o;
}
寄生式继承其实就是对原型式继承的二次封装,在二次封装的过程中对新对象进行扩展。
六.寄生组合式继承
function inheritPrototype(subClass, superClass){
var p = inheritObject(superClass.prototype);
p.constructor = subClass;
subClass.prototype = p;
}
function superClass(id){
this.books = ['html', 'css', 'js'];
this.id = id;
}
superClass.prototype.showBooks = function(){
console.log(this.books);
}
function subClass(id, name){
superClass.call(this, id);
this.name = name;
}
inheritPrototype(subClass, superClass);
var instance1 = new subClass(100, 'jack');
var instance2 = new subClass(200, 'tom');
instance1.books.push('php');
console.log(instance1.books);//['html', 'css', 'js', 'php']
console.log(instance2.books);//['html', 'css', 'js']
console.log(instance1.showBooks());//['html', 'css', 'js', 'php']
寄生组合式继承是一种近乎完美的继承方式,需要注意的是在子类原型上添加方法的时候不能直接给prototype对象赋值对象