许多OO语言都支持两种继承方式:
而 ECMA 只支持实现继承,主要依靠原型链来实现
原型链继承
核心思想:重写原型对象,代之以一个新类型的实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| function Parent() { this.name = 'Parent'; }
Parent.prototype.getName = function () { console.log(this.name); }
function Child() {}
Child.prototype = new Parent();
const child1 = new Child(); child1.getName();
const child2 = new Child(); child2.getName();
|
优点:
- 父类新增原型方法/属性,子类都能访问到
- 简单,易于实现
缺点:
- 引用类型的属性被所有实例共享
- 创建子类实例时,不能像父类构造函数传参
借用构造函数继承(经典继承)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| function Parent(name) { this.name = name; this.color = ['red']; }
function Child(name) { Parent.call(this, name); }
const child1 = new Child('Child1'); child1.color.push('green'); console.log(child1);
const child2 = new Child('Child2'); child2.color.push('blue'); console.log(child2);
|
优点:
- 避免了引用类型的属性被所有子类实例所共享
- 可以在子类中向父类构造函数传参
缺点:
- 无法实现函数复用
- 在父类原型中定义的方法,对于子类不可见
组合继承
这种方式的核心思想在于:通过结合原型链继承和经典继承两种方式,融合了二者的优点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| function Parent(name) { this.name = name; this.color = ['red']; }
Parent.prototype.getName = function () { console.log(this.name); }
function Child(name, age) { Parent.call(this, name); this.age = age; }
Child.prototype = new Parent(); Child.prototype.constructor = Child;
const child1 = new Child('Child1', 18); child1.color.push('green'); console.log(child1);
const child2 = new Child('Child2', 17); child2.color.push('blue'); console.log(child2);
|
缺点:
原型式继承
核心思想:用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了个可以随意增添属性的实例或对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| function createObj(o) { function F() {} F.prototype = o; return new F(); }
const person = { name: 'person', friends: ['daisy', 'kelly'] }
const person1 = createObj(person); const person2 = createObj(person);
person1.name = 'person1'; console.log(person1);
person2.friends.push('taylor'); console.log(person2);
console.log(person);
|
缺点:
寄生式继承
核心思想:创建一个仅用于封装继承过程的函数,并在该函数中以某种形式来增强对象,最后返回该对象(和原型式继承紧密相关)
1 2 3 4 5 6 7 8 9 10 11 12
| function createObj(o) { let clone = Object.create(o); clone.sayHi = function() { console.log('Hi'); } return clone; }
const person = { name: 'person', friends: ['daisy', 'kelly'] }
|
缺点:
寄生组合式继承
核心思想:结合借用构造函数产地参数和寄生模式实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| function createObj(o) { function F() {} F.prototype = o; return new F(); }
function inheritPrototype(child, parent) { const prototype = createObj(parent.prototype); prototype.constructor = parent; child.prototype = prototype; }
function Parent(name) { this.name = name; this.color = ['red']; }
Parent.prototype.getName = function () { console.log(this.name); }
function Child(name, age) { Parent.call(this, name); this.age = age; }
inheritPrototype(Child, Parent);
Parent.prototype.getAge = function () { console.log(this.age); }
const child1 = new Child('Child1', 18); child1.color.push('green'); console.log(child1);
const child2 = new Child('Child2', 17); child2.color.push('blue'); console.log(child2);
|
优点:
参考
《JavaScript高级程序教程(第3版)》