JavaScript中的继承方式详解
字数 797 2025-11-05 23:47:39

JavaScript中的继承方式详解

描述
JavaScript中的继承是指一个对象能够访问另一个对象的属性和方法。由于JavaScript基于原型,继承主要通过原型链实现。ES5有几种经典继承方式,ES6引入了class语法糖。理解不同继承方式有助于编写可维护的面向对象代码。

逐步讲解

  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;
        this.colors = ['red'];
      }
      function Child(name) {
        Parent.call(this, name); // 核心:在子类上下文中执行父类构造函数
      }
      
      const child1 = new Child('Child1');
      child1.colors.push('blue');
      console.log(child1.colors); // ['red', 'blue'](独立属性)
      
      const child2 = new Child('Child2');
      console.log(child2.colors); // ['red'](不受child1影响)
      
    • 缺点:无法继承父类原型上的方法。
  3. 组合继承

    • 原理:结合原型链继承和构造函数继承,既继承原型方法又保证实例属性独立。
    • 步骤
      1. 使用构造函数继承父类实例属性。
      2. 使用原型链继承父类原型方法。
    • 示例
      function Parent(name) {
        this.name = name;
      }
      Parent.prototype.sayName = function() { console.log(this.name); };
      
      function Child(name, age) {
        Parent.call(this, name); // 第1次调用Parent:继承实例属性
        this.age = age;
      }
      Child.prototype = new Parent(); // 第2次调用Parent:继承原型方法
      Child.prototype.constructor = Child; // 修复constructor指向
      
      const child = new Child('Tom', 10);
      child.sayName(); // "Tom"
      
    • 缺点:父类构造函数被调用两次(性能浪费)。
  4. 原型式继承

    • 原理:基于现有对象创建新对象,ES5的Object.create()方法实现此模式。
    • 示例
      const parent = { name: 'Parent', friends: ['Alice'] };
      const child1 = Object.create(parent); // 以parent为原型创建对象
      child1.name = 'Child1';
      child1.friends.push('Bob');
      
      const child2 = Object.create(parent);
      console.log(child2.friends); // ['Alice', 'Bob'](共享引用属性)
      
    • 适用场景:简单对象继承,无需构造函数。
  5. 寄生组合继承

    • 原理:优化组合继承,避免两次调用父类构造函数。通过中间对象连接子类和父类原型。
    • 步骤
      1. 使用构造函数继承实例属性。
      2. 创建一个空函数,将其原型指向父类原型。
      3. 将子类原型指向空函数的实例。
    • 示例
      function inheritPrototype(Child, Parent) {
        const F = function() {}; // 空构造函数
        F.prototype = Parent.prototype;
        Child.prototype = new F(); // 仅继承原型链,不调用父类构造函数
        Child.prototype.constructor = Child;
      }
      
      function Parent(name) {
        this.name = name;
      }
      function Child(name, age) {
        Parent.call(this, name); // 仅1次构造函数调用
        this.age = age;
      }
      inheritPrototype(Child, Parent);
      
    • 优点:ES6以前最完美的继承方式。
  6. ES6的class继承

    • 原理classextends是语法糖,底层仍基于原型链,通过super调用父类。
    • 示例
      class Parent {
        constructor(name) {
          this.name = name;
        }
        sayName() { console.log(this.name); }
      }
      
      class Child extends Parent {
        constructor(name, age) {
          super(name); // 相当于Parent.call(this, name)
          this.age = age;
        }
      }
      
      const child = new Child('Tom', 10);
      child.sayName(); // "Tom"
      
    • 注意:必须先调用super()才能使用this

总结

  • 优先使用ES6的class继承,简洁且无历史包袱。
  • 理解底层原型链机制有助于调试复杂继承关系。
  • 寄生组合继承是理解class继承原理的关键。
JavaScript中的继承方式详解 描述 JavaScript中的继承是指一个对象能够访问另一个对象的属性和方法。由于JavaScript基于原型,继承主要通过原型链实现。ES5有几种经典继承方式,ES6引入了class语法糖。理解不同继承方式有助于编写可维护的面向对象代码。 逐步讲解 原型链继承 原理 :将子类的原型对象指向父类的实例,从而通过原型链访问父类属性。 示例 : 缺点 : 所有子类实例共享父类引用属性(如数组),修改会相互影响。 无法向父类构造函数传参。 构造函数继承 原理 :在子类构造函数中调用父类构造函数,通过 call 或 apply 改变this指向。 示例 : 缺点 :无法继承父类原型上的方法。 组合继承 原理 :结合原型链继承和构造函数继承,既继承原型方法又保证实例属性独立。 步骤 : 使用构造函数继承父类实例属性。 使用原型链继承父类原型方法。 示例 : 缺点 :父类构造函数被调用两次(性能浪费)。 原型式继承 原理 :基于现有对象创建新对象,ES5的 Object.create() 方法实现此模式。 示例 : 适用场景 :简单对象继承,无需构造函数。 寄生组合继承 原理 :优化组合继承,避免两次调用父类构造函数。通过中间对象连接子类和父类原型。 步骤 : 使用构造函数继承实例属性。 创建一个空函数,将其原型指向父类原型。 将子类原型指向空函数的实例。 示例 : 优点 :ES6以前最完美的继承方式。 ES6的class继承 原理 : class 和 extends 是语法糖,底层仍基于原型链,通过 super 调用父类。 示例 : 注意 :必须先调用 super() 才能使用 this 。 总结 优先使用ES6的class继承,简洁且无历史包袱。 理解底层原型链机制有助于调试复杂继承关系。 寄生组合继承是理解class继承原理的关键。