一、原型链继承
子类的原型是父类的实例,子类可以继承的所有私有属性和方法,并且可以继承父类的原型上的属性和方法
function Teacher() {}
Teacher.prototype = {
constructor: Teacher,
name: '老师',
tSkill: 'js'
}
function Student(name) {
this.name = name
this.mSkill = 'html'
}
Student.prototype = new Teacher()
const s = new Student('小明')
console.log(s)
缺点:来自父类的所有属性和方法(包括原型)都会被继承,有时我们并不需要这么多属性
二、利用call/apply调用父类构造函数,借用
父类的属性和方法
function Teacher(name) {
this.name = name
}
Teacher.prototype = {
tSkill: 'js'
}
function Student(name, age) {
Teacher.call(this, name) // 利用call/apply调用父类构造函数
this.age = age
}
const s = new Student('小明', 18)
console.log(s)
缺点:只能借用父类构造函数中的属性,无法借用父类原型上的属性
这种方式是借用,不是继承,因为子类的实例不属于父类
function Person() {}
function Teacher() {
Person.apply(this)
}
// Teacher.prototype = Person.prototype // 打开注释的这行,便是继承
const t = new Teacher()
console.log(t instanceof Person) // false
三、圣杯模式
最标准的面向对象实现模式:基于原型的构造函数模式
若直接写Student.prototype = Teacher.prototype
,则在更改Student原型上属性时会同步更改到Teacher原型。通过圣杯模式则可以避免这种情况
圣杯模式:声明一个构造函数,它的原型继承于父类,它的实例赋值给子类的原型,这样子类的原型中就继承了父类的原型,在操作子类的原型时不会操作到父类的原型
function Teacher() {
this.name = '老师'
this.tSkill = 'js'
}
Teacher.prototype = {
bSkill: 'html'
}
const t = new Teacher()
function Student() {
this.name = '学生'
}
function Buffer() {
this.bufferName = '我是中间件'
}
Buffer.prototype = Teacher.prototype // Buffer的实例的原型将会有Teacher原型上的属性
const b = new Buffer()
Student.prototype = b // Student的实例的原型和Buffer的实例b保持一致
Student.prototype.age = 18 // 更改子类原型上的属性,b的实例会同步更改,但实例不会影响到原型,所以不会更改到Buffer和Teacher
const s = new Student()
console.log(t)
console.log(b)
console.log(s)
封装inherit函数:
function Teacher() {
this.name = '老师'
}
Teacher.prototype = {
tSkill: 'js'
}
// function Buffer() {}
// Buffer.prototype = Teacher.prototype
// const b = new Buffer()
function Student() {
this.name = '学生'
}
// Student.prototype = b
inherit(Student, Teacher)
Student.prototype.age = 10
const t = new Teacher()
const s = new Student()
console.log(t)
console.log(s, s.tSkill)
function inherit(Target, Origin) {
function Buffer() {}
Buffer.prototype = Origin.prototype
Target.prototype = new Buffer()
Target.prototype.constructor = Target // 还原构造器
Target.prototype.super_class = Origin // 设置继承源
}
inherit函数还可以通过闭包的形式定义
const inherit = (function () {
const Buffer = function () {}
return function (Target, Origin) {
Buffer.prototype = Origin.prototype
Target.prototype = new Buffer()
Target.prototype.constructor = Target
Target.prototype.spuer_class = Origin
}
})()