原型继承
1)核心: 将父类实例作为子类原型
2)优点: 方法复用
3)缺点:
1、创建子类实例的时候,不能传参
2、子类实例共享了父类的构造函数的引用属性,比如foods
3、无法实现多继承
//父类
function School(name,foods){
this.name=name
this.foods=['甜品']
this.person=function(){
console.log(this.name+'吃'+this.foods);
}
}
//父类原型对象添加方法
School.prototype.print=function(){
console.log(this.name,this.foods);
}
//子类
function Student(){}
//原型继承
Student.prototype=new School()
//纠正constructor指向
Student.prototype.constructor=Student
//创建实例
let stu1=new Student()
let stu2=new Student()
stu1.name='jack'
stu1.foods.push('罐头')
console.log(stu1.name);
console.log(stu1.foods);
stu1.person()
stu1.print()
console.log('——————————————————————————————————————————————');
stu2.name='rose'
stu2.foods.push('香蕉')
console.log(stu2.name);
console.log(stu2.foods);
stu2.person()
stu2.print()
构造函数继承
1)核心: 借用父类的构造函数来增强子类实例,等于复制父类的实例属性给子类
2)优点: 实例之间独立
1、创建子类实例,可以向父类构造函数传参数。
2、子类实例不共享父类的构造函数的引用属性。如foods属性
3、可实现多继承(通过多个call或者apply继承多个父类)
3)缺点
1、父类的方法不能复用
由于方法再父构造函数中定义,导致方法不能复用(因为每次创建子类实例都要创建一遍方法)
2、子类实例,继承不了父类原型上的属性(因为没有用到原型)
function School(name,foods){
this.name=name
this.foods=['甜品']
this.person=function(){
console.log(this.name+'吃'+this.foods);
}
}
School.prototype.print=function(){
console.log(this.name,this.foods);
}
function Student(name,money){
School.call(this,name)
this.money=money
}
let stu1=new Student('jack',20000)
let stu2=new Student('rose',20000)
stu1.foods.push('苹果')
stu1.person()
console.log(stu1.name)
console.log(stu1.money)
console.log(stu1.foods);
console.log('——————————————————————————————————————');
stu2.foods.push('梨子')
stu2.person()
console.log(stu2.name)
console.log(stu2.money)
console.log(stu2.foods);
console.log(stu2.print);//undefined
组合继承
1)核心: 通过调用父类构造函数,继承父类的属性和方法并保留传参的优点;然后通过将父类实例作为子类原型,实现函数的复用
2)优点
1、保留构造函数的优点:创建子类实例,可以向父类构造函数传参
2、保留原型链优点:父类的方法定义在父类的原型对象上,可以实现方法复用
3、不共享父类的引用属性,比如foods属性
3)缺点:
1、由于调用了2次父类的构造方法,会存在一份多余的父类实例对象。Student.prototype的父类属性和方法会被School.call(this)拷贝来的实例属性屏蔽掉
2、注意组合继承方式,要记得修复Student.prototype.constructor的指向
function School(name,foods){
this.name=name
this.foods=['甜品']
this.person=function(){
console.log(this.name+'吃'+this.foods);
}
}
School.prototype.print=function(){
console.log(this.name,this.foods);
}
function Student(name,money){
School.call(this,name)
this.money=money
}
Student.prototype = new School()
Student.prototype.constructor = Student
let stu1=new Student('jack',20000)
let stu2=new Student('rose',20000)
stu1.foods.push('苹果')
stu1.person()
console.log(stu1.name)
console.log(stu1.money)
console.log(stu1.foods);
console.log('——————————————————————————————————————');
stu2.foods.push('梨子')
stu2.person()
console.log(stu2.name)
console.log(stu2.money)
console.log(stu2.foods);
stu2.print()
组合继承优化1
1)核心: 通过这种方式,砍掉父类的实例属性,这样在调用父类的构造函数的时候,就不会初始化两次实例,避免组合继承的缺点。
2)优点:
1、只调用一次父类的构造函数
2、保留构造函数的优点:创建子类实例,可以向父类构造函数传参
3、保留原型链的优点:父类的实例方法定义在父类的原型对象上,可以实现方法复用
3)缺点:
1、修正构造函数的指向后,父类实例的构造函数指向,同时也发生变化
function School(name,foods){
this.name=name
this.foods=['甜品']
this.person=function(){
console.log(this.name+'吃'+this.foods);
}
}
School.prototype.print=function(){
console.log(this.name,this.foods);
}
function Student(name,money){
School.call(this,name)
this.money=money
}
Student.prototype = School.prototype
Student.prototype.constructor=Student
let stu1=new Student('jack',20000)
let stu2=new Student('rose',20000)
stu1.foods.push('苹果')
stu1.person()
console.log(stu1.name)
console.log(stu1.money)
console.log(stu1.foods);
console.log('——————————————————————————————————————');
stu2.foods.push('梨子')
stu2.person()
console.log(stu2.name)
console.log(stu2.money)
console.log(stu2.foods);
stu2.print()
组合继承优化2(寄生式组合继承)
完美!!!!
function School(name,foods){
this.name=name
this.foods=['甜品']
this.person=function(){
console.log(this.name+'吃'+this.foods);
}
}
School.prototype.print=function(){
console.log(this.name,this.foods);
}
function Student(name,money){
School.call(this,name)
this.money=money
}
Student.prototype = Object.create(School.prototype)
Student.prototype.constructor = Student
let stu1=new Student('jack',20000)
let stu2=new Student('rose',20000)
stu1.foods.push('苹果')
stu1.person()
console.log(stu1.name)
console.log(stu1.money)
console.log(stu1.foods);
console.log('——————————————————————————————————————');
stu2.foods.push('梨子')
stu2.person()
console.log(stu2.name)
console.log(stu2.money)
console.log(stu2.foods);
stu2.print()
类继承
super :调用父类中的构造函数(constructor)
class Father {
constructor(x,y){
this.x=x
this.y=y
}
sum(){
console.log(this.x+this.y);
}
}
class Son extends Father{
constructor(x,y){
super(x,y)
}
}
var son = new Son(1,2)
son.sum()