前言
继承的目的其实就是改变原型链
比如说,继承之前的原型链是 son -> Son.prototype -> Object.prototype -> null
而继承之后的原型链是 son -> Son.prototype -> Father.prototype -> Object.prototype -> null
一、原型继承
实现方式:把父类的实例作为子类的原型
缺点:子类的实例中共享了父类原型上的引用属性
// 字面量方式
var father = {
data: [1, 2]
}
var son = Object.create(father)
son.data.push(3)
console.log(son.data) // [1,2,3]
console.log(father.data) // [1,2,3]
// 构造函数方式
function Father() {
this.data = {
name: 'zs'
}
}
function Son() {}
var father = new Father()
Son.prototype = father
var son = new Son()
son.data.name = 'ls'
console.log(son.data) // { name: 'ls' }
console.log(father.data) // { name: 'ls' }
二、构造函数继承
实现方式:调用父类的构造函数,改变this的指向,指向子类
缺点:只能继承父类的属性,不能继承父类的方法
function Father(age) {
this.info = {
name: 'zs'
}
this.age = age
}
Father.prototype.getName = function () {
console.log(this.info.name)
}
function Son(age) {
Father.call(this, age)
}
var father = new Father(18)
var son = new Son(20)
son.info.name = 'ls'
console.log(father.info) // { name: 'zs' }
console.log(father.age) // 18
father.getName() // zs
console.log(son.info) // { name: ''ls }
console.log(son.age) // 20
son.getName() // son.getName is not a function
三、组合继承
实现方式:构造函数继承 + 原型继承
缺点:调用父类的构造函数两次,造成消耗
function Father(age) {
this.info = {
name: 'zs'
}
this.age = age
}
Father.prototype.getName = function () {
console.log(this.info.name)
}
function Son(age) {
// 第一次调用父类的构造函数
Father.call(this, age) // 构造函数继承
}
// 第二次调用父类的构造函数
Son.prototype = new Father() // 原型继承
Son.prototype.constructor = Son // 修复子类构造函数的指向
var father = new Father(18)
var son = new Son(20)
son.info.name = 'ls'
console.log(father.info) // { name: 'zs' }
console.log(father.age) // 18
father.getName() // zs
console.log(son.info) // { name: ''ls }
console.log(son.age) // 20
son.getName() // ls
四、寄生组合式继承
实现方式: 构造函数继承 + 原型继承,原型继承的方式调整,不继承父类的属性
function Father(age) {
this.info = {
name: 'zs'
}
this.age = age
}
Father.prototype.getName = function () {
console.log(this.info.name)
}
function Son(age) {
// 第一次调用父类的构造函数
Father.call(this, age) // 构造函数继承
}
// 第二次调用父类的构造函数
Son.prototype = Object.create(Father.prototype) // 原型继承
Son.prototype.constructor = Son // 修复子类构造函数的指向
var father = new Father(18)
var son = new Son(20)
son.info.name = 'ls'
console.log(father.info) // { name: 'zs' }
console.log(father.age) // 18
father.getName() // zs
console.log(son.info) // { name: ''ls }
console.log(son.age) // 20
son.getName() // ls
五、ES6 extends继承
class Father{
constructor(name){
this.name = name
}
}
// extends相当于 Son.prototype.__proto__ = Father.prototype
class Son extends Father{
// 若写了 constructor 则必须要写 super
constructor(){
// super相当于 Father.call(this)
super()
}
}