在JavaScript中,继承是一种非常重要的概念。它允许创建一个对象,在这个对象上可以进行特定的操作,并且可以从其他对象中继承属性和方法。虽然JavaScript本身并不支持类,但是使用原型链和构造函数,我们可以实现类似于面向对象编程(OOP)的继承。
组合式继承
组合式继承是JavaScript中最常用的继承方式之一。它结合了原型链继承和借用构造函数继承的优点,同时避免它们的缺点。
基本思路
组合式继承的基本思路是:
- 使用借用构造函数继承来继承父类的属性。
- 使用原型链继承来继承父类的方法。
这种方式能够让子类既拥有父类的属性,也能够使用父类的方法。
实现示例
下面是一个使用组合式继承实现的示例代码:
-------- ------------ - --------- - ----- - ------------------------- - ---------- - ------------------- -- ---- -- --------------- -- -------- ----------- ---- - -- -------- ----------------- ------ -------- - ---- - -- ----- --------------- - --- --------- ---------------------- - ---------- - -------------- -- ----------- ----- ------ -- ----- ----- - --- ------------ ---- ----------------- -- --------- -- ---- -- --- --------------- -- ---- -- -- ----- ---
在上面的示例代码中,我们定义了一个Parent构造函数来创建父类对象,并为其添加了一个sayHello方法。然后,我们定义了一个Child构造函数来创建子类对象,并借用构造函数继承了父类的name属性。接着,我们使用原型链继承来继承了父类的sayHello方法,并在子类中添加了一个sayAge方法。
最后,我们通过new关键字来创建了一个Child类的实例对象,并调用了它的sayHello和sayAge方法,都能够正常输出结果。
存在的问题
虽然组合式继承是一种很好的继承方式,但是也存在一些问题:
- 第一次调用
Parent()
构造函数时,会创建一个实例对象并且将该实例对象赋值给Child.prototype
。这个实例对象包含了所有从父类中继承来的属性,但是它也多余地调用了一次父类的构造函数。因此,在创建子类实例时,会先创建一个不必要的实例对象。 - 在
Child.prototype
中定义的那些方法和属性,都是在这个不必要的实例对象上创建的。然后该实例对象被赋值给Child.prototype
,最后再通过new
关键字创建子类实例时,又会创建一个新的实例对象。这样就会导致我们创建了两个实例对象,其中一个是不必要的。
优化
为了解决上述问题,我们可以使用另一种方式来实现组合式继承。
-------- ------------ - --------- - ----- - ------------------------- - ---------- - ------------------- -- ---- -- --------------- -- -------- ----------- ---- - ----------------- ------ -------- - ---- - -- ------------------- --------------- - -------------------------------- --------------------------- - ------ ---------------------- - ---------- - -------------- -- ----------- ----- ------ -- ----- ----- - --- ----- ---------------------------------------------------------- ---------- -------------------------------------------------------------------------------------