js实现继承的6种方式

本文总结自js高程

原型链

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Super
function SuperType() {
this.property = true;
}
SuperType.prototype.getSuperProperty = function () {
return this.property;
}
// Sub
function SubType() {
this.subProperty = false;
}
SubType.prototype = new SuperType();
SubType.prototype.getSubProperty = function () {
return this.subProperty;
}
var instance1 = new SubType();
instance1 instanceof SuperType === true; // true
var instance2 = new SubType();
instance2.property === instance1.property; // true
  • 优点:

    1. 父类SuperType实例上的属性和方法 和 SuperType原型上的属性和方法,都会被子类SubType继承;
  • 缺点:

    1. 子类SubType所有实例共享 一个SuperType的实例,该实例原型上的属性,一个被修改,所有的子类SubType实例都会被修改;
    2. 无法为父类SuperType的构造函数传递参数。

借用构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Super
function SuperType(name) {
this.color = ['red', 'green', 'blue'];
this.name = name;
}
// Sub
function SubType(name, age) {
SuperType.call(this, name);
this.age = age;
}
var instance1 = new SubType('wn', 12);
var instance2 = new SubType('fyt', 11);
instance1.color.push('xxx');
console.log(instance1, instance2);
  • 优点:

    1. 可以为父类SuperType的构造函数传递参数。
  • 缺点:

    1. 无法复用父类SubType上的函数,每个子类SubType的实例,都会创建一个同名的函数。

组合继承

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
// Super
function SuperType(name) {
this.color = ['red', 'green', 'blue'];
this.name = name;
}
SuperType.prototype.getName = function() {
return this.name;
}
// Sub
function SubType(name, age) {
SuperType.call(this, name);
this.age = age;
}
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.getAge = function () {
return this.age;
}
var instance1 = new SubType('wn', 12);
instance1.color.push('xxx');
console.log(instance1.getName());
console.log(instance1.getAge());
var instance2 = new SubType('fyt', 11);
console.log(instance2.getName());
console.log(instance2.getAge());
console.log(instance1, instance2);
  • 优点:

    1. 可以复用父类SuperType原型上的函数。
    2. 可以为父类SuperType的构造函数传递参数。
  • 缺点:

    1. SuperType 需要 new 两次

原型式继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Object.create() 等价
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] };
var anotherPerson = object(person); anotherPerson.name = "Greg"; anotherPerson.friends.push("Rob");
var yetAnotherPerson = object(person); yetAnotherPerson.name = "Linda"; yetAnotherPerson.friends.push("Barbie");
console.log(person.friends);
//"Shelby,Court,Van,Rob,Barbie"
  • 优点:

    1. 可以直接为一个对象(实例)扩展一个新对象。
  • 缺点:

    1. 简单把对象放在新函数的原型上,不涉及到SuperType类及其构造函数初始化。

寄生式继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
function createAnother(original) {
var clone = object(original);
// 增强对象
clone.sayHi = function () {
console.log('hi');
}
return clone;
}
  • 优点:

    1. 可以直接为一个对象(实例)扩展(或增强)一个新对象。
  • 缺点:

    1. 简单把对象放在新函数的原型上,不涉及到SuperType类及其构造函数初始化。

寄生组合式

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
40
41
42
43
44
45
46
47
48
49
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
// inheritPrototype
function inheritPrototype (subType, superType)
{
// swallow clone
var prototype = object(superType.prototype);
prototype.constructor = subType;
subType.prototype = prototype;
}
// Super
function SuperType(name) {
this.color = ['red', 'green', 'blue'];
this.name = name;
}
SuperType.prototype.getName = function() {
return this.name;
}
// Sub
function SubType(name, age) {
SuperType.call(this, name);
this.age = age;
}
inheritPrototype(SubType, SuperType);
// inheritPrototype函数实现内容,如上:
// var prototype = object(SuperType.prototype);
// prototype.constructor = SubType;
// SubType.prototype = prototype;
SubType.prototype.getAge = function () {
return this.age;
}
var instance1 = new SubType('wn', 12);
instance1.color.push('xxx');
console.log(instance1.getName());
console.log(instance1.getAge());
var instance2 = new SubType('fyt', 11);
console.log(instance2.getName());
console.log(instance2.getAge());
console.log(instance1, instance2);
  • 优点:

    1. 完美。
  • 缺点:

    1. 完美。