当前位置:  首页>> 技术小册>> ES6入门指南

类是 ES6 新增的一个语法糖,用于实现面向对象编程。在类的继承方面,ES6 引入了子类的概念,让我们能够更加方便地实现类的继承。在本章节中,将结合代码示例,深入探讨 ES6 子类的用法和实现原理。


1、子类的定义和基本用法

子类是基于父类的一种扩展,可以继承父类的属性和方法,并且可以添加自己的属性和方法。在 ES6 中,我们可以使用 extends 关键字来定义子类,语法如下:

  1. class ChildClass extends ParentClass {
  2. // 子类的其他代码
  3. }

其中,ChildClass 表示子类的名称,ParentClass 表示父类的名称。子类中可以定义自己的属性和方法,这些属性和方法会覆盖父类中同名的属性和方法。同时,子类也可以使用 super 关键字来调用父类的构造函数和方法。下面是一个简单的示例代码:

  1. class Animal {
  2. constructor(name) {
  3. this.name = name;
  4. }
  5. sayName() {
  6. console.log(`My name is ${this.name}`);
  7. }
  8. }
  9. class Dog extends Animal {
  10. bark() {
  11. console.log('Woof!');
  12. }
  13. }
  14. const myDog = new Dog('Fido');
  15. myDog.sayName(); // 输出 "My name is Fido"
  16. myDog.bark(); // 输出 "Woof!"

在这个示例中,Animal 是父类,Dog 是子类。Dog 继承了 Animal 的构造函数和 sayName 方法,并且新增了自己的 bark 方法。通过 super 关键字,Dog 在构造函数中调用了父类的构造函数,同时在 sayName 方法中调用了父类的 sayName 方法。

2、子类的实现原理

在 JavaScript 中,类的继承是通过原型链实现的。ES6 的子类继承也是基于原型链的,它的实现原理可以归纳为以下几个步骤:

  • 创建子类的实例对象,同时将父类的构造函数和属性复制到子类实例中;
  • 将子类的原型设置为父类的实例,从而让子类可以继承父类的方法;
  • 在子类中定义自己的属性和方法。

在上面的示例代码中,Dog 继承了 Animal 的构造函数和方法,这些属性和方法都被复制到了 Dog 的实例对象中。同时,Dog 的原型被设置为 Animal 的实例,从而让 Dog 可以继承 Animal 的方法。在 Dog 中定义的 bark 方法则是子类自己新增的方法。

注意:当子类的原型设置为父类的实例时,父类的构造函数会被调用一次。这是因为在设置子类的原型时,JavaScript 引擎会自动调用父类的构造函数来初始化子类的实例。在示例代码中,Dog 的实例对象被创建时,父类的构造函数被自动调用一次,因此我们在 Dog 的构造函数中必须调用 super 关键字来初始化父类的属性。

3、子类的继承方式

在 ES6 中,子类有两种继承方式:类继承和构造函数继承。下面分别介绍这两种继承方式的用法和特点。

3.1 类继承
类继承是 ES6 中子类的默认继承方式,它通过 extends 关键字来实现。在类继承中,子类继承了父类的所有属性和方法,并且可以添加自己的属性和方法。在子类中,通过 super 关键字来调用父类的构造函数和方法。

类继承的一个特点是,子类的实例对象是父类的实例对象。也就是说,子类继承了父类的构造函数和属性,因此子类的实例对象和父类的实例对象是相同的类型。下面是一个示例代码:

  1. class Parent {
  2. constructor(name) {
  3. this.name = name;
  4. }
  5. sayName() {
  6. console.log(`My name is ${this.name}`);
  7. }
  8. }
  9. class Child extends Parent {
  10. constructor(name, age) {
  11. super(name);
  12. this.age = age;
  13. }
  14. sayAge() {
  15. console.log(`I am ${this.age} years old`);
  16. }
  17. }
  18. const parent = new Parent('Tom');
  19. const child = new Child('Jerry', 6);
  20. console.log(parent instanceof Parent); // 输出 true
  21. console.log(child instanceof Child); // 输出 true
  22. console.log(child instanceof Parent); // 输出 true
  23. parent.sayName(); // 输出 "My name is Tom"
  24. child.sayName(); // 输出 "My name is Jerry"
  25. child.sayAge(); // 输出 "I am 6 years old"

在这个示例中,Parent 是父类,Child 是子类。Child 继承了 Parent 的构造函数和 sayName 方法,并且新增了自己的 sayAge 方法。通过 super 关键字,Child 在构造函数中调用了父类的构造函数,同时在 sayName 方法中调用了父类的 sayName 方法。

3.2 构造函数继承
构造函数继承是 ES6 中另一种子类继承的方式,它通过在子类中调用父类的构造函数来实现继承。在构造函数继承中,子类不会继承父类的原型对象,因此子类的实例对象不是父类的实例对象。下面是一个示例代码:

  1. function Parent(name) {
  2. this.name = name;
  3. }
  4. Parent.prototype.sayName = function() {
  5. console.log(`My name is ${this.name}`);
  6. };
  7. function Child(name, age) {
  8. Parent.call(this, name);
  9. this.age = age;
  10. }
  11. Child.prototype.sayAge = function() {
  12. console.log(`I am ${this.age} years old`);
  13. };
  14. const parent = new Parent('Tom');
  15. const child = new Child('Jerry', 6);
  16. console.log(parent instanceof Parent); // 输出 true
  17. console.log(child instanceof Child); // 输出 true
  18. console.log(child instanceof Parent); // 输出 false
  19. parent.sayName(); // 输出 "My name is Tom"
  20. child.sayName(); // 报错,sayName 方法不在 Child 的原型对象中
  21. child.sayAge(); // 输出 "I am 6 years old"

在这个示例中,Parent 和 Child 的定义方式与前面示例相同。在 Child 的构造函数中,通过 Parent.call(this, name) 调用了父类的构造函数,以实现继承父类的属性。Child 的原型对象中新增了自己的 sayAge 方法,但没有继承父类的原型对象中的 sayName 方法,因此在 child.sayName() 中会报错。

构造函数继承的一个特点是,它只继承了父类的属性,而没有继承父类的原型对象。因此,构造函数继承的适用场景相对较少,一般只在需要继承父类的属性时使用。

小结
ES6 的子类继承机制使得 JavaScript 中的面向对象编程更加方便和灵活。通过继承父类的属性和方法,子类可以更加高效地实现自己的逻辑,而不必重复编写已经实现过的代码。同时,子类也可以通过新增自己的属性和方法来满足自己的需求。


该分类下的相关小册推荐: