继承
- 原型链继承
- 借用构造函数继承
- 组合继承
- 原型继承
- 寄生式继承
- 寄生组合继承
- ES6 的 extends
原型链继承
// 继承的本质就是重写原型链
function SuperType() {
this.superName = 'superName'
this.colors = ["red", "blue", "green"]
}
SuperType.prototype.getSuperName = function() {
return this.superName;
}
function SubType() {}
// 关键:创建 SuperType 实例并赋值(重写)给 SubType 原型对象(prototype)
SubType.prototype = new SuperType()
const instance = new SubType()
instance.getSuperName() // 'superName'
// 缺陷:多个实例的引用类型属性指向相同的内存,存在篡改的可能
const instance2 = new SubType();
instance2.colors.push('yellow')
instance.colors // ["red", "blue", "green", "yellow"]
instance.colors === instance2.colors // true
构造函数继承
function SuperType() {
this.superName = 'superName'
this.colors = ["red", "blue", "green"]
}
SuperType.prototype.getSuperName = function() {
return this.superName;
}
function SubType() {
// 关键 理解call
SuperType.call(this)
}
const instance = new SubType()
instance.getSuperName === undefined // true
// 缺陷
// 1、只能继承父类的属性/方法,不能继承原型的属性/方法
// 2、每个实例都有父类函数的方法,无法复用,会影响性能
组合继承
// 组合继承 = 原型链继承 + 借用构造函数继承
function SuperType() {
this.superName = 'superName'
this.colors = ["red", "blue", "green"]
}
SuperType.prototype.getSuperName = function() {
return this.superName;
}
function SubType() {
// 借用构造函数继承
SuperType.call(this)
}
// 原型链继承
SubType.prototype = new SuperType()
// 重写 constructor 指向 SubType
SubType.prototype.constructor = SubType
const instance = new SubType()
const instance2 = new SubType()
instance.colors.push('yellow')
console.log(instance.colors) // ["red", "blue", "green", "yellow"]
console.log(instance2.colors) // ["red", "blue", "green"]
// 缺陷
// 原型上会存在和实例相同属性/方法
原型继承
let parent = {
name: "Nicholas",
colors: ["red", "blue", "green"],
getName: function() {
return this.name;
}
}
/*
Object.create(parent)
function _create(obj) {
const newObj = {}
newObj.prototype = obj
return newObj
}
Object.create 等价于 _create
*/
const son = Object.create(parent)
son.name = 'Greg'
const son1 = Object.create(parent)
son1.name = 'Linda'
console.log(son.name) // 'Greg'
console.log(son1.name) // 'Greg'
// 缺陷
// 1、创建原型的方法是浅拷贝,引用类型属性指向相同的内存,存在篡改的可能
// 2、无法传参
son1.colors.push('yellow')
console.log(son.colors) // ["red", "blue", "green", "yellow"]
son.getName === son1.getName // true
寄生式继承
let parent = {
name: "Nicholas",
colors: ["red", "blue", "green"],
getName: function() {
return this.name;
}
}
// 封装原型,为原型新增属性和方法,以增强函数
function clone(obj) {
let clone = Object.create(obj)
clone.colors = function() {
return this.colors
}
return clone
}
const son = clone(parent)
son.name = 'Greg'
// 缺陷和原型继承一致
寄生组合
// 组合继承
function Parent() {
this.name = 'Nicholas'
this.colors = ['red', 'blue', 'green']
}
// 支持传参
function Child(name, age) {
Parent.call(this, name)
this.age = age
}
// Object.create(Parent.prototype) 解决了原型上存在和实例相同属性/方法的缺陷
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child
let person = new Child('Greg', 18)
let person2 = new Child('Linda', 19)
// 解决引用类型属性篡改问题
person.colors.push('orange')
person2.colors.push('yellow')
console.log(person)
console.log(person2)
ES6 extends
就是寄生组合模式
function _extends(subType, superType){
subType.prototype = Object.create(superType.prototype)
subType.prototype.constructor = subType;
Object.setPrototypeOf
? Object.setPrototypeOf(subType, superType)
: subType.__proto__ = superType
}
function Parent(name) {
this.name = name
}
Parent.prototype.getName = function() {
return this.name
}
function Child(name, age) {
Parent.call(this, name)
this.age = age
}
// 继承
_extends(Child, Parent);
const child = new Child('Greg', 18)
const child1 = new Child('Linda', 19)
console.log(child.name, child.age, child.getName())
console.log(child1.name, child1.age, child1.getName())
// 好了,你会写继承了!!哈哈
总结
- 原型链
- 解决问题:
- 存在缺陷:多个实例的引用类型属性指向相同的内存,存在篡改的可能
- 借用构造函数继承
- 解决问题:
- 存在缺陷:只能父类的属性/方法,不能继承原型的属性/方法
- 组合继承
- 解决问题:
- 存在缺陷:原型和实例会存在相同的属性和方法
- 原型式继承
- 解决问题:
- 存在缺陷:多个实例的引用类型属性指向相同的内存,存在篡改的可能
- 寄生式继承
- 解决问题:
- 存在缺陷:
- 寄生组合式继承
- 解决问题:
- 存在缺陷: