JavaScript 继承的实现方式有哪些?

JavaScript 提供多种继承方式,如原型链和组合继承,用于对象创建和方法传递。

JavaScript 中等 继承 面向对象编程 OOP

JavaScript 提供多种继承实现方式,基于原型机制,每种方式有不同原理和应用场景。以下是常见方法的解释:

  1. 原型链继承
    通过将子类的原型设置为父类实例实现继承。
    • 原理:子类实例可访问父类原型上的属性和方法。
    • 示例代码
      function Parent() {
        this.name = 'Parent';
      }
      Parent.prototype.sayName = function() {
        console.log(this.name);
      };
      function Child() {}
      // 设置子类原型为父类实例
      Child.prototype = new Parent();
      const child = new Child();
      child.sayName(); // 输出 'Parent'
      
    • 优势:简单易懂。
    • 劣势:所有实例共享父类引用属性;无法传递参数给父构造函数。
  2. 借用构造函数继承
    在子类构造函数中调用父类构造函数,实现属性和方法的复制。
    • 原理:使用 callapply 将父类的 this 绑定到子类实例。
    • 示例代码
      function Parent(name) {
        this.name = name;
      }
      function Child(name, age) {
        Parent.call(this, name); // 借用父类构造函数
        this.age = age;
      }
      const child = new Child('Tom', 18);
      console.log(child.name); // 输出 'Tom'
      
    • 优势:解决属性共享问题,可传递参数。
    • 劣势:无法继承父类原型上的方法。
  3. 组合继承
    结合原型链和借用构造函数的优点,是目前推荐的方式。
    • 原理:用借用构造处理属性,原型链处理原型方法。
    • 示例代码
      function Parent(name) {
        this.name = name;
      }
      Parent.prototype.sayName = function() {
        console.log(this.name);
      };
      function Child(name, age) {
        Parent.call(this, name); // 处理属性
        this.age = age;
      }
      Child.prototype = new Parent(); // 处理原型方法
      const child = new Child('Alice', 10);
      child.sayName(); // 输出 'Alice'
      
    • 优势:属性独立,方法可共享。
    • 劣势:需两次调用父构造函数。
  4. 原型式继承
    使用对象直接基于一个原类型对象创建新实例。
    • 原理:通过自定义函数创建对象,将传入的对象作为新对象的原型。
    • 示例代码
      const parent = {
        name: 'parent',
        sayHello: function() {
          console.log('Hello from ' + this.name);
        }
      };
      const child = Object.create(parent);
      child.name = 'child';
      child.sayHello(); // 输出 'Hello from child'
      
    • 优势:轻量级实现继承。
    • 劣势:属性和方法可被覆盖。
  5. 寄生组合式继承
    优化的组合继承方式,避免重复调用父构造函数。
    • 原理:通过拷贝父类原型继承方法,无需实例化。
    • 示例代码
      function inheritPrototype(child, parent) {
        const proto = Object.create(parent.prototype);
        proto.constructor = child;
        child.prototype = proto;
      }
      function Parent() {
        this.name = 'Parent';
      }
      function Child() {
        Parent.call(this);
        this.name = 'Child';
      }
      inheritPrototype(Child, Parent);
      const child = new Child();
      console.log(child.name); // 输出 'Child'
      
    • 优势:性能最佳,无冗余调取。
    • 劣势:代码稍复杂。
  6. ES6 类继承
    使用 extends 关键字简化语法,基于类语法。
    • 原理:语法糖,编译为原型机制。
    • 示例代码
      class Parent {
        constructor(name) {
          this.name = name;
        }
        sayName() {
          console.log(this.name);
        }
      }
      class Child extends Parent {
        constructor(name, age) {
          super(name); // 调用父类构造函数
          this.age = age;
        }
      }
      const child = new Child('Bob', 20);
      child.sayName(); // 输出 'Bob'
      
    • 优势:现代、简洁、易读。
    • 劣势:仅适用于现代 ES6+ 环境。