原型链继承
每个构造函数都有一个原型对象,原型有一个属性指回构造函数,而实例有一个内部指针指向原型。如果原型是另一个类型的实例呢?
这意味着这个原型本身有一个内部指针指向另一个原型,相应地另一个原型也有一个指针指向另一个构造函数。这样就在实例和原型之间构造了一条原型链。
通过修改子类的原型为父类的实例,从而实现子类可以访问到父类构造函数以及原型上的属性或者方法。
function Parent() {
//属性
this.name = 'fedaily';
//实例方法
this.sleep = function(){
console.log(this.name + "正在睡觉");
}
}
//父类原型方法
Parent.prototype.eat = function(food = 'apple') {
console.log(this.name +'正在吃'+ food);
}
//空子类
function Child() {}
// 这里也可以直接写出Child.prototype = Parent.prototype
// 但是这样就不能访问到父类的构造函数的属性了,即this.name
Child.prototype = new Parent();
Child.prototype.name = 'Bob';
var child = new Child();
child.eat();
缺点:
- 在包含有引用类型的数据时,会被所有的子类实例共享,其中一个子类实例进行修改,会导致所有其他子类实例的这个值都会改变
- 在创建子类型的时候不能向超类型传递参数
构造函数继承(call)
通过修改父类构造函数this实现的继承。
function Parent() {
//属性
this.name = 'Amy';
//实例方法
this.sleep = function(){
console.log(this.name + "正在睡觉");
}
}
function Child(){
//继承了Parent
Parent.call(this);
this.name = "BOB";
}
let child = new Child();
组合继承
同时结合原型链继承、构造函数继承,是使用最多的继承方式。
function Parent(){
this.name = "Amy";
this.age = 20;
}
Parent.prototype.eat = function(){
return this.name + this.age + 'eat sleep';
}
function Child(){
//第一次调用父类构造函数
Parent.call(this);
this.name = 'Bob';
this.topic = 'fe';
}
//第二次调用父类构造函数
Child.prototype = new Parent();
//需要重新设置子类的constructor,Child.prototype = new Parent()相当于子类的原型对象完全被覆盖了
Child.prototype.construct = Child;
let child = new Child();
child.eat();
寄生式组合继承
在组合继承的基础上,解决了父类构造函数调用两次的问题
function Parent(){
this.name = 'Amy';
this.age = 20;
}
//父类原型方法
Parent.prototype.eat = function(){
return this.name + this.age + 'eat sleep';
}
//子类
function Child(){
//继承父类属性
Parent.call(this);
this.name = 'Bob';
this.age = 28;
}
//继承父类方法(执行匿名函数)
(function(){
//创建空类
let Super = function(){};
Super.prototype = Parent.protype;
//父类的实例作为子类的原型
Child.prototype = new Super();
})();
// 修复构造函数指向问题
Child.prototype.constructor = Child;
let child = new Child();
原型式继承(实例继承)
function Parent(){
this.name = 'Amy';
this.age = 20;
}
function Child(){
let instance = new Parent();
instance.name = "Bob";
instance.topic = 'fe';
return instance;
}
let child = new Child();
ES6继承
ES6继承是使用关键字先创建父类的实例对象this,最后在子类class中修改this
class Parent{
constructor(){
this.name = 'Amy';
this.age = 20;
}
eat(){
console.log(`${this.name} ${this.age} eat food`);
}
}
//子类继承
class Child extends Parent{
constructor(){
super();
}
eat(){
super.eat();
this.topic = 'fe';
}
}
let child = new Child();
child.eat();