继承

原型链

实现原型链的基本模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function SuperType() {
this.property = true;
}
SuperType.property.getSuperValue = function() {
return this.property;
}
function SubType() {
this.subproperty = false;
}
// 继承了 SuperType
SubType.property = new SuperType();
SubType.property.getSubValue = function() {
return this.subproperty;
}
var instance = new SubType();
console.log(instance.getSuperValue()); // true

原型链

其实上图中的 SuperType Prototype 是 Object 构造函数的一个实例,上图将其省略了

确定原型和实例的关系

1
2
3
console.log(instance instanceof Object); // true;
console.log(instance instanceof SuperType); // true;
console.log(instance instanceof SubType); // true;
1
2
3
console.log(Object.property.isPropertyOf(instance)); // true
console.log(SuperType.property.isPropertyOf(instance)); // true
console.log(SubType.property.isPropertyOf(instance)); // true

原型链的问题

  1. 引用类型值的原型属性会被所有实例共享。因此要在构造函数中定义属性,而不要在原型中定义属性
  2. 没有办法在不影响所有实例的前提下,给超类的构造函数传递参数

借用构造函数

在子类型构造函数的内部调用超类型构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function SuperType() {
this.colors = ['red', 'blue', 'green'];
}
function SubType() {
SuperType.call(this);
}
var instance1 = new SubType();
instance1.colors.push('black');
console.log(instance1.colors); // red, blue, green, black
var instance2 = new SubType();
console.log(instance2.colors); // red, blue, green

缺点:在超类构造函数中定义的方法无法复用;超类原型中的方法对子类型不可见

组合继承

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
function SuperType() {
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
SuperType.property.sayName = function() {
console.log(this.name);
}
function SubType(name, age) {
SuperType.call(this, name);
this.age = age;
}
SubType.property = new SuperType();
SubType.property.constructor = SubType;
SubType.property.sayAge = function() {
console.log(this.age);
}
var instance1 = new SubType('a', 29);
instance1.colors.push('black');
console.log(instance1.colors); // red, blue, green, black
instance1.sayName(); // a
instance1.sayAge(); // 29
var instance2 = new SubType('b', 30);
console.log(instance2.colors); // red, blue, green
instance2.sayName(); // b
instance2.sayAge(); // 30

原型式继承

1
2
3
4
5
function object(o) {
function F() {}
F.prototype = o;
return new F();
}

返回的实例的原型为o

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var person = {
name: 'a',
friends: ['A', 'B', 'C']
}
var anotherPerson = object(person);
anotherPerson.name = 'b';
anotherPerson.friends.push('D');
var yetAnotherPerson = object(person);
yetAnotherPerson.name = 'c';
yetAnotherPerson.friends.push('E');
console.log(person.friends); // A, B, C, D, E

寄生式继承

1
2
3
4
5
6
7
8
function createAnother(original) {
// 使用了 原型式继承 中的object方法
var clone = object(original);
clone.sayHi = function() {
console.log('hi');
}
return clone;
}

寄生组合式继承

组合继承调用了两次超类构造函数的代码
为了解决这个问题,寄生组合式继承借用构造函数来继承属性,通过原型链的混成形式继承方法

基本思路:不必为了指定子类型的原型而调用超类的构造函数

基本模式如下:

1
2
3
4
5
function inheritPrototype(subType, superType) {
var prototype = object(superType.prototype);
prototype.constructor = subType;
subType.prototype = prototype;
}

使用方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function SuperType() {
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
SuperType.property.sayName = function() {
console.log(this.name);
}
function SubType(name, age) {
SuperType.call(this, name);
this.age = age;
}
inheritPrototype(SubType, SuperType);
SubType.property.sayAge = function() {
console.log(this.age);
}

坚持原创技术分享,您的支持将鼓励我继续创作!