原型链继承
function Parent () {
this.name = 'hello world'
}
Parent.prototype.getName = function () {
console.log(this.name)
}
function Child () {}
Child.prototype = new Parent()
const child = new Child()
console.log(child.getName()) // hello world
原型链继承会有一下问题:
- 引用类型的属性被所有实例共享
- 在创建Child的实例的时候,不能向Parent传参
function Parent () {
this.name = ['Jack', 'Tom']
}
function Child () {}
Child.prototype = new Parent()
const child = new Child()
child.name.push('haha')
const child2 = new Child()
console.log(child2.name) // ['Jack', 'Tom', 'haha']
借用构造函数
function Parent (name) {
this.name = name
}
function Child (name, age) {
Parent.call(this, name)
this.age = age
}
const child1 = new Child('xiao ming', 25)
const child2 = new Child('xiao hong', 28)
console.log(child1.age) // 25
console.log(child1.name) // xiao ming
console.log(child2.age) // 28
console.log(child2.name) // xiao hong
借用构造函数优点:
- 避免了引用属性被所有实例所共享
- 可以在子类可以拥有自己的属性 缺点:
- 不能继承父类原型上的属性和方法
组合继承
既然原型链继承和借用构造函数继承都有各自的缺点,那能不能把两者结合起来,答案是肯定的
function Parent (name) {
this.name = name
}
Parent.prototype.getName = function () {
console.log(this.name)
}
function Child (name, age) {
Parent.call(this, name)
this.age = age
}
Child.prototype.getInfo = function () {
console.log('my name is' + this.name + 'i am' + this.age + 'old')
}
Child.prototype = new Parent()
const child1 = new Child('Tom', 21)
const child2 = new Child('Mary', 19)
console.log(child1.getInfo())
console.log(child1.getInfo())
原型式继承
function create (o) {
function F () {}
F.prototype = o
return new F()
}
以上就是对ES5中Object.create()的模拟实现,将传入的对象作为创建对象的原型,这个缺点跟原型链是一样的,引用类型的属性始终都会被所有子类所共享
寄生式继承
寄生式继承就是创建一个近用于封装继承过程的函数,该函数在内部以某种方式增强对象,最后再将这个对象返回
function createPlus (o) {
const clone = Object.create(o)
clone.sayName = function () {
console.log('hi')
}
return clone
}
const person = {
name: 'Tom'
}
const p1 = createPlus(person)
console.log(p1.sayName())
缺点:跟借用构造函数模式一样,每次创建对象都会创建一遍方法。
寄生组合式继承
function Parent (name) {
this.name = name
this.colors = ['red', 'green', 'yellow']
}
function Child (name, age) {
Parent.call(this, name)
this.age = age
}
// Object.create()的模拟实现
function F () {}
F.prototype = Parent.prototype
Child.prototype = new F()
const child = new Child('Jack', 18)
最后我们封装一下这个继承方法
function Parent (name) {
this.name = name
this.colors = ['red', 'green', 'yellow']
}
function Child (name, age) {
Parent.call(this, name)
this.age = age
}
function inherit (Parent, Child) {
const prototype = Object.create(Parent.prototype)
prototype.constructor = Child
Child.prototype = prototype
}
inherit(Parent, Child)
这种方式的高效率体现它只调用了一次 Parent 构造函数,并且因此避免了在 Parent.prototype 上面创建不必要的、多余的属性。与此同时,原型链还能保持不变;因此,还能够正常使用 instanceof 和 isPrototypeOf。开发人员普遍认为寄生组合式继承是引用类型最理想的继承范式