(js使用es5的特性模拟类,而不借助于新增语法糖__学习笔记)
1. 原型链继承
通过原型继承多个引用类型的属性和方法
function Father(){
this.name = 'lalal'
}
Father.prototype.sayName = function(){...}
function Child(){
this.age = 18
}
Child.prototype = new Father() //重点!这个赋值重写了最初的原型
let instance = new Child()
🔔关键点:子类没有使用默认原型,替换为新的对象,这个对象为父类的实例。Child.prototype == Father.prototype
🙅♀️缺点:原型中包含的引用值会在所有实例之间共享(所以通常定义在构造函数中)
子类在实例化的时候不能给父类传参
2.盗用构造函数/对象伪装/经典继承
在子类的构造函数中调用父类构造函数,解决引用值问题
function Father(){
this.colors = ['red','blue']
}
function Child(){
Father.call(this)
}
let instance = new Child()
相当于实例化的时候执行父类构造函数,则每个实例都有自己的属性
🔔关键点:在子类中call父类构造函数
✅好处:实例之间的引用类型不相互影响、子类构造函数中可以向父类传参
🙅♀️缺点:必须在构造函数中定义方法,函数不能重用;子类不能访问父类原型上定义的方法(构造函数中的可以,prototype写的不可以)
3.组合继承
综合原型链+盗用构造函数,使用原型链继承属性和方法,盗用构造函数继承实例属性
(prortotype指向后原型链上的方法都可以访问到,实例化的时候盗用父类构造函数可以自身维护引用类型的属性)
function Father(name){
this.name = name
this.colors = ['red','blue']
}
Father.prototype.say = function(){console.log('123')}
function Child(name,age){
Father.call(this,name)
this.age = age
}
Child.prototype = new Father()
🔔关键点:既在子类构造函数中call,又指向new的父类
✅好处:引用类型不会相互影响、可以用instanceof识别、可以向父类构造函数传参、可以继承父类原型上的方法
🙅♀️缺点:效率问题,父类构造函数调用两次
4.原型式继承
即使不定义类型也可以通过原型实现信息共享==>适用于本来有一个对象,在这个基础上修改
function object(o){
function F(){} //创建一个临时构造函数
F.prototype = o //在原来对象的基础上,本质是对传入对象进行一次浅复制
return new F()
}
5.寄生式继承
创建一个实现继承的函数,增强对象再返回这个对象
function create(o){
let clone = object(o) //通过调用函数创建新对象(也可以使用别的函数创建)
clone.say = function(){...}
return clone
}
寄生式给对象添加函数也会导致难以服用
6.寄生式组合继承
不通过调用父类构造函数给子类原型赋值,而是获得父类原型的副本。通过盗用构造函数继承属性,混合式原型链继承方法
function inheritPrototype(child,fater){
let prototype = objet(fater.prototype)
prototype.constructor = child
child.prototype = prototype
}
//构造Father同上
function Child(name,age){
Father.call(this,name)
this.age = age
}
inheritPrototype(Child,Fater)
只调用了一次父类的构造函数,避免了原型链上不必要的属性。