Logo

JS继承的几种方式:从原型链到现代ES6

author
YGHub·2025-05-12·0·字数:1258 字·阅读时间:5 分钟

继承是JavaScript面向对象编程的核心机制,允许对象复用属性和方法,提升代码可维护性。

从早期的原型链到现代ES6的class语法,经历了多次演进,为开发者提供了灵活的选择。无论是构建复杂前端应用还是Node.js后端,理解继承方式都能帮助你设计更优雅的代码。

为什么需要JS继承?

JavaScript基于原型(prototype)的对象模型,继承通过原型链或构造函数实现代码复用。继承的典型场景包括:

  • 代码复用:子类复用父类的属性和方法。
  • 层次结构:构建如动物->狗->拉布拉多的对象体系。
  • 框架开发:如React组件继承或Node.js模块设计。

根据MDN,ES6(ES2015)引入的class语法使继承更直观,但传统方式仍广泛存在于旧代码和特定场景。以下6种继承方式基于ES2022+(2025年5月最新标准)。

方式1:原型链继承

为什么使用? 原型链继承通过设置子类原型为父类实例,实现属性和方法共享,简单直观。

实现方法

  1. 定义父类和子类:
    javascript
    function Animal(name) {
    this.name = name;
    }
    Animal.prototype.say = function () {
    console.log(`${this.name} says hi`);
    };
     
    function Dog(name, breed) {
    this.name = name;
    this.breed = breed;
    }
     
  2. 设置原型链:
    javascript
    Dog.prototype = new Animal();
    Dog.prototype.constructor = Dog;
     
  3. 测试代码:
    javascript
    const dog = new Dog("Max", "Labrador");
    dog.say();
     
  4. 验证:输出:
    Max says hi
     

优缺点

  • 优点:简单,共享父类方法。
  • 缺点:父类实例属性被所有子类共享,修改可能影响其他实例。

方式2:构造函数继承(借用构造函数)

为什么使用? 通过callapply借用父类构造函数,继承实例属性,避免原型共享问题。

实现方法

  1. 定义父类和子类:
    javascript
    function Animal(name) {
    this.name = name;
    }
    Animal.prototype.say = function () {
    console.log(`${this.name} says hi`);
    };
     
    function Cat(name, color) {
    Animal.call(this, name);
    this.color = color;
    }
     
  2. 测试代码:
    javascript
    const cat = new Cat("Whiskers", "White");
    console.log(cat.name, cat.color);
     
  3. 验证:输出:
    Whiskers White
     

优缺点

  • 优点:独立实例属性,避免共享问题。
  • 缺点:无法继承父类原型方法(如say)。

方式3:组合继承

为什么使用? 结合原型链和构造函数继承,既继承实例属性又继承原型方法,最常用的传统方式。

实现方法

  1. 定义父类和子类:
    javascript
    function Animal(name) {
    this.name = name;
    }
    Animal.prototype.say = function () {
    console.log(`${this.name} says hi`);
    };
     
    function Dog(name, breed) {
    Animal.call(this, name);
    this.breed = breed;
    }
     
  2. 设置原型链:
    javascript
    Dog.prototype = new Animal();
    Dog.prototype.constructor = Dog;
     
  3. 测试代码:
    javascript
    const dog = new Dog("Max", "Labrador");
    dog.say();
    console.log(dog.breed);
     
  4. 验证:输出:
    Max says hi
    Labrador
     

优缺点

  • 优点:兼顾属性和方法继承。
  • 缺点:调用两次父类构造函数,性能略低。

方式4:寄生继承

为什么使用? 通过创建中间对象增强子类,灵活扩展父类功能,适合临时继承。

实现方法

  1. 定义寄生函数:
    javascript
    function createChild(parent) {
    const child = Object.create(parent);
    child.extra = function () {
    console.log("Extra functionality");
    };
    return child;
    }
     
  2. 使用寄生继承:
    javascript
    const animal = {
    name: "Generic",
    say: function () {
    console.log(`${this.name} says hi`);
    },
    };
    const dog = createChild(animal);
    dog.name = "Max";
     
  3. 测试代码:
    javascript
    dog.say();
    dog.extra();
     
  4. 验证:输出:
    Max says hi
    Extra functionality
     

优缺点

  • 优点:灵活,适合增强对象。
  • 缺点:无法复用构造函数逻辑。

方式5:寄生组合继承

为什么使用? 优化组合继承,避免两次调用父类构造函数,性能更好,常用于复杂项目。

实现方法

  1. 定义继承函数:
    javascript
    function inheritPrototype(child, parent) {
    child.prototype = Object.create(parent.prototype);
    child.prototype.constructor = child;
    }
     
  2. 定义父类和子类:
    javascript
    function Animal(name) {
    this.name = name;
    }
    Animal.prototype.say = function () {
    console.log(`${this.name} says hi`);
    };
     
    function Cat(name, color) {
    Animal.call(this, name);
    this.color = color;
    }
    inheritPrototype(Cat, Animal);
     
  3. 测试代码:
    javascript
    const cat = new Cat("Whiskers", "White");
    cat.say();
    console.log(cat.color);
     
  4. 验证:输出:
    Whiskers says hi
    White
     

优缺点

  • 优点:高效,避免冗余调用。
  • 缺点:实现稍复杂。

方式6:ES6类继承

为什么使用? ES6的classextends提供现代、简洁的继承语法,内置优化,适合2025年新项目。

实现方法

  1. 定义父类和子类:
    javascript
    class Animal {
    constructor(name) {
    this.name = name;
    }
    say() {
    console.log(`${this.name} says hi`);
    }
    }
     
    class Dog extends Animal {
    constructor(name, breed) {
    super(name);
    this.breed = breed;
    }
    }
     
  2. 测试代码:
    javascript
    const dog = new Dog("Max", "Labrador");
    dog.say();
    console.log(dog.breed);
     
  3. 验证:输出:
    Max says hi
    Labrador
     

优缺点

  • 优点:语法简洁,内置优化。
  • 缺点:不适用于旧浏览器(需Babel转译)。

优化建议

为高效使用JS继承的几种方式

  1. 优先ES6类:新项目使用classextends,代码清晰,性能优。
  2. 寄生组合继承:传统项目需高效继承时使用,避免组合继承的冗余。
  3. 原型链谨慎:避免共享属性问题,适合简单场景。
  4. 工具支持:使用TypeScript增强继承类型安全:
    typescript
    class Animal {
    name: string;
    constructor(name: string) {
    this.name = name;
    }
    }
    class Dog extends Animal {}
     
  5. 性能测试:大项目中使用console.time比较继承方式性能:
    javascript
    console.time("Inheritance");
    const dog = new Dog("Max", "Labrador");
    console.timeEnd("Inheritance");
     

从原型链的朴素到ES6类的优雅,为开发者提供了多样化的工具。

原型链继承简单但共享属性有风险,构造函数继承独立但无法复用方法,组合继承全面但性能稍逊,寄生继承灵活,寄生组合继承高效,ES6类继承现代简洁。

Preview

点个赞 ~

版权申明: © 本文著作权归YGHub所有,未经YGHub网授权许可,禁止第三方以任何形式转载和使用本文内容。