Open
Description
在《JS 高级程序设计》这本书里列举了 JS 实现继承的多种方式以及对应的优缺点。
原型链继承
原型链继承通过 new
操作符将子类的原型和父类的原型链接起来。代码示例如下:
function Parent() {
this.name = 'parent'
}
Parent.prototype.getName = function() {
console.log(this.name)
}
function Child() {
}
Child.prototype = new Parent()
var child = new Child()
console.log(child.getName) // parent
缺点:
- 引用类型的属性在所有实例间共享,修改一个实例值影响其它
- 创建子类实例时不能向父类传参
构造函数继承
通过在子类构造函数借用 call
调父类来实现,代码如下:
function Parent() {
this.name = 'parent'
}
function Child() {
Parent.call(this)
}
var child = new Child()
console.log(child.name) // parent
缺点:
- 每次创建实例都会创建一遍构造函数中的方法
- 不能做到属性方法共享
组合继承
把原型链继承和构造函数继承组合起来了:
function Parent(name) {
this.name = name
}
Parent.prototype.getName = function() {
console.log(this.name)
}
function Child(name, age) {
Parent.call(this)
this.age = age
}
Child.prototype = new Parent()
Child.prototype.constructor = Child
var child = new Child('child', 18)
console.log(child.name) // child
console.log(child.age) // 18
缺点:
- 调用了两次父类
原型式继承
这种继承就是 ES5 Object.create 的模拟实现:
function create(o) {
function F() {}
F.prototype = 0
return new F()
}
缺点:
- 与原型链一样,引用类型属性的值始终会在实例间共享
寄生式继承
创建一个用于实现继承的函数,函数内部新建一个对象,以某种形式增强对象后返回它,代码如下:
function createObj(o) {
var clone = Object.create(o)
clone.sayName = function() {
console.log('say hi')
}
return clone
}
缺点:
- 每次调用都会创建一遍方法
寄生组合式继承
这是对 组合继承
的改进,是一种完美实现 JS 继承的解决方案。组合继承最大的缺点在于调用了两次父类构造函数:
// 第一次
Child.prototype = new Parent()
// 第二次
Parent.call(this)
这带来的问题是子类实例和子类构造函数的 prototype 上会有多余的属性。为了精益求精,避免两次调用所带来的浪费,解决方法是不让子类原型与父类实例挂钩,而是让子类原型间接地访问到父类原型,这其中的关键就是前面的 原型式继承
:通过一个空函数来中转,让子类原型直接去 new 空函数,而空函数的原型又是父类,这样就间接访问到了父类原型。寄生组合式的代码示例如下:
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
}
function inherit(child, parent) {
function F() {}
F.prototype = parent.prototype
child.prototype = new F()
}
inherit(Child, Parent)
Child.prototype.constuctor = Child
var child = new Child('child', 18)
console.log(child) // {name: 'child', age: 18}
寄生组合式继承是比较完美的继承方式。