function Father(name) {
// 实例属性
this.name = name
// 实例方法
this.sayName = function() {
console.log(this.name)
}
}
// 原型属性
Father.prototype.age = 19
// 原型方法
Father.prototype.sayAge = function() {
console.log(this.age)
}
1.原型链继承
将父类的实例作为子类的原型
function Son(name) {
this.name = name
}
Son.prototype = new Father()
const son = new Son('son')
son.sayName() // son
son.sayAge() // 19
优点:
简单,易于实现
父类新增原型方法、原型属性,子类都能访问到
缺点:
无法实现多继承,因为原型一次只能被一个实例更改
来自原型对象的所有属性被所有实例共享
创建子类实例时,无法向父构造函数传参
2.构造继承
复制父类的实例属性给子类
function Son(name) {
Father.call(this, "Son props")
this.name = name
}
const son = new Son('son')
son.sayName() // son
son.sayAge() // 报错,无法继承父类原型
console.log(son instanceof Son) // true
console.log(son instanceof Father) // false
优点:
解决了原型链继承中实例共享父类引用属性的问题
创建子类实例时,可以向父类传参
可以实现多继承(call 多个父类对象)
缺点:
实例并不是父类的实例,只是子类的实例
只能继承父类实例属性和方法,不能继承原型属性和方法
无法实现函数复用,每个子类都有父类实例函数的副本,影响性能
3.组合继承
将原型链和构造函数组合一起,使用原型链实现对原型属性和方法的继承,使用构造函数实现实例属性继承
function Son(name) {
// 第一次调用父类构造器 子类实例增加父类实例
Father.call(this, 'Son props')
this.name = name
}
Son.prototype = new Father()
const son = new Son('son')
son.name // 'son'
son.sayAge() // 19
son.sayName() // 'son'
son instanceof Son // true
son instanceof Father // true
son.constructor === Father // true
son.constructor === Son // false
优点:
弥补了构造继承的缺点,可以同时继承实例属性方法和原型属性方法
既是子类的实例,也是父类的实例
可以向父类传参
函数可以复用
缺点:
调用了两次父类构造函数,生成了两份实例
构造函数(constructor)指向问题
4.寄生组合继承
通过寄生方式,砍掉父类的实例属性,避免组合继承生成两份实例的缺点
function Son(name) {
Father.call(this)
this.name = name
}
Son.prototype = Object.create(Father.prototype)
Son.prototype.constructor = Son
const son = new Son('son')
son.sayAge // 19
son.sayName // son
son instanceof Father // true
son instanceof Son // true
son.constructor === Father // false
son.constructor === Son // true
优点:
比较完美(js 实现继承首选方式)
缺点:
实现方式较为复杂