继承

原型链继承

​ 原型链继承是一种实现对象之间继承关系的方法,通过让一个对象的原型指向另一个对象,从而使得子对象可以继承父对象的属性和方法

​ 步骤:

  1. 创建父对象:首先创建一个父对象,可以是一个普通对象或者一个构造函数。
  2. 创建子对象:然后创建一个子对象,通过将子对象的原型指向父对象来实现继承。
  3. 继承属性和方法:子对象通过原型链继承了父对象的属性和方法,可以访问和使用它们
1
2
3
4
5
6
7
8
9
10
11
// 创建了一个父对象parent,其中包含一个sayHello方法。然后我们创建了一个子对象child,通过Object.create()方法将子对象的原型指向父对象
let parent = {
sayHello: function() {
console.log('Hello from parent!');
}
};
// 创建一个子对象,并将其原型指向父对象
let child = Object.create(parent);

// 子对象继承父对象的方法
child.sayHello(); // Output: Hello from parent!

其他:

  1. 原型链继承的问题:原型链继承有一个问题,就是所有子对象共享父对象的属性和方法。这意味着如果一个子对象修改了继承的属性或方法,会影响到所有其他子对象。可以思考如何解决这个问题。
  2. 多层继承:可以尝试创建多层继承关系,即子对象的原型指向另一个子对象,从而实现多层继承。
  3. 构造函数和原型链结合:可以结合构造函数和原型链继承来实现更灵活的继承方式,即使用构造函数定义对象的特定属性,使用原型链继承共享的属性和方法

构造函数继承

​ 构造函数继承是一种实现对象之间继承关系的方法,通过在子构造函数中调用父构造函数来实现属性的继承。这种继承方式也被称为经典继承或伪经典继承。

​ 步骤:

  1. 定义父构造函数:首先定义一个父构造函数,该构造函数包含要被继承的属性和方法。
  2. 定义子构造函数:然后定义一个子构造函数,通过在子构造函数中调用父构造函数来继承父构造函数的属性。
  3. 继承属性:子对象通过构造函数继承父对象的属性,每个子对象都有自己的一份属性副本。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 定义了一个父构造函数Animal和一个子构造函数Dog。在子构造函数中,通过Animal.call(this, name)调用父构造函数来继承父对象的属性。这样子对象就可以拥有父对象的属性和方法。
function Animal(name) {
this.name = name;
}

// 在父构造函数的原型上添加方法
Animal.prototype.sayName = function() {
console.log('My name is ' + this.name);
};

// 定义子构造函数
function Dog(name, breed) {
// 继承父构造函数的属性
Animal.call(this, name);
this.breed = breed;
}

// 创建一个子对象
let myDog = new Dog('Buddy', 'Labrador');

// 子对象继承父对象的方法
myDog.sayName(); // Output: My name is Buddy

其他:

  1. 原型链与构造函数继承结合:可以结合原型链和构造函数继承来实现更灵活的继承方式,即使用构造函数继承属性,使用原型链继承共享的方法。
  2. 继承多个构造函数:可以尝试在子构造函数中调用多个父构造函数来继承多个对象的属性。
  3. 继承方法:除了继承属性,还可以尝试在子构造函数中继承父对象的方法,而不仅仅是属性。

组合式继承

​ 组合式继承(Combination Inheritance)是一种结合了构造函数继承和原型链继承的继承方式,可以解决构造函数继承和原型链继承各自的缺点,实现属性和方法的有效继承

​ 步骤:

  1. 构造函数继承:通过在子构造函数中调用父构造函数来继承属性。
  2. 原型链继承:通过将子构造函数的原型指向一个父构造函数的实例来继承方法。
  3. 优点:组合式继承结合了构造函数继承和原型链继承的优点,避免了它们各自的缺点,实现了属性和方法的有效继承
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
// 定义了一个父构造函数Animal和一个子构造函数Dog。在子构造函数中,通过Animal.call(this, name)调用父构造函数来继承父对象的属性,然后通过Dog.prototype = Object.create(Animal.prototype)来继承父对象的方法。这样子对象就可以拥有父对象的属性和方法。
function Animal(name) {
this.name = name;
}

// 在父构造函数的原型上添加方法
Animal.prototype.sayName = function() {
console.log('My name is ' + this.name);
};

// 定义子构造函数
function Dog(name, breed) {
// 继承父构造函数的属性
Animal.call(this, name);
this.breed = breed;
}

// 继承父构造函数的方法
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

// 创建一个子对象
let myDog = new Dog('Buddy', 'Labrador');

// 子对象继承父对象的属性和方法
myDog.sayName(); // Output: My name is Buddy
  1. 优化组合式继承:可以进一步优化组合式继承,避免调用两次父构造函数,以提高性能。
  2. ES6类继承:可以尝试使用ES6中的类继承语法来实现继承,更加简洁和易读。
  3. 混合继承:可以结合多种继承方式,如构造函数继承、原型链继承、组合式继承等,来满足不同的继承需求。

寄生组合式继承

​ 寄生组合式继承(Parasitic Combination Inheritance)是对组合式继承的一种优化,通过使用寄生式继承来减少调用父构造函数的次数,提高性能。

​ 优缺点:

  1. 组合式继承的缺点:组合式继承会调用两次父构造函数,一次是在子构造函数中继承属性时,另一次是在设置子构造函数的原型时。这样会导致父构造函数被调用两次,影响性能。
  2. 寄生组合式继承的优化:寄生组合式继承通过使用一个空函数作为中介,来减少对父构造函数的不必要调用,提高性能。
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
// 定义了一个寄生函数inheritPrototype,它通过创建父构造函数原型的副本,并将其赋值给子构造函数的原型,来实现寄生组合式继承。这样就避免了多次调用父构造函数,提高了性能。
function Animal(name) {
this.name = name;
}

// 在父构造函数的原型上添加方法
Animal.prototype.sayName = function() {
console.log('My name is ' + this.name);
};

// 定义寄生函数
function inheritPrototype(subType, superType) {
let prototype = Object.create(superType.prototype); // 创建父构造函数原型的副本
prototype.constructor = subType; // 修正constructor属性
subType.prototype = prototype; // 设置子构造函数的原型
}

// 定义子构造函数
function Dog(name, breed) {
Animal.call(this, name); // 继承父构造函数的属性
this.breed = breed;
}

// 使用寄生式继承
inheritPrototype(Dog, Animal);

// 创建一个子对象
let myDog = new Dog('Buddy', 'Labrador');

// 子对象继承父对象的属性和方法
myDog.sayName(); // Output: My name is Buddy

其他:

  1. 继承多个父对象:可以尝试在寄生函数中实现继承多个父对象的属性和方法。
  2. 优化寄生式继承:可以进一步优化寄生式继承的实现方式,提高代码的可读性和性能。
  3. 使用工厂模式:可以结合工厂模式来改进继承的实现方式,实现更灵活的继承方式