首先先定义一个父类
function Person(name = 'person') {
this.name = name
this.say = function(thing) {
console.log(`${this.name} say ${thing}`)
}
}
Person.prototype.eat = function(food) {
console.log(`${this.name} is eating ${food}!`)
}
1. 原型链继承
核心: 将父类的实例作为子类的原型
function Male(age) {
this.age = age
}
Male.prototype = new Person()
Male.prototype.constructor = Male
Male.prototype.sex = 'male'
var l = new Male(20)
console.log(l.gae) // 20
console.log(l.name) // person
l.say('hello') //person say hello
l.eat('meat') //person is eating meat!
l instanceof Male // true
l instanceof Person //true
l.constructor //Male
优点:
- 关系纯粹,通过Male构造的实例 l 既是 Male 的实例,也是Person的实例
- 父类原型新增的方法和属性,子类都能访问到
- 简单,便于实现
缺点
- 创建子类实例时,无法向父类构造函数传参,因为继承之前,父类构造函数就已经执行
- 要想为子类原型新增属性和方法,必须要在new Person()这样的语句之后执行
- 来自原型对象的所有属性被所有实例共享
- 无法实现多继承
2.构造函数继承
核心:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类(没用到原型)
function Male(name, age) {
Person.call(this, name)
this.age = 20
}
var l = new Male('l', 20)
3.实例继承
function Male(name. age) {
let instance = new Person(name)
instane.age = 20
return instane
}
缺点
- 实例是父类的实例,不是子类的实例
- 不持支多继承
有点 - 不限制调用方式,可以使用new Male也可以直接使用Male
4.拷贝继承
function Male() {
let instance = new Animal()
for ( let key in instance ) {
this[key] = instance[key
}
return instance
}
特点:
- 支持多继承
缺点 - 效率低,内存占用高
- 无法获取父类不可枚举的方法
5. 组合继承(原型链继承 + 构造函数继承)
function Male(age) {
Person.call(this)
this.age = 20
}
Male.prototype = new Person()
Male.prototype.constructor = Male
let l = new Male(20)
优点:
- 解决了方案2的问题
- 既是子类的实例,也是父类的实例
- 不存在引用属性共享问题
- 可传参
- 函数可复用
缺点
- 调用了两次父类构造函数,生成了两份实例
6.寄生组合继承
function Male() {}
function compose(a, b) {
function fn() {}
fn.prototype = b.prototype
a.prototype = new fn()
a.prototype.constructor = a
return a
}
compose(Male, Person)
var l = new Male()