js 函数继承与类继承的区别是什么?

一、 语法差异

1、函数继承(原型链 / 构造函数组合)

通过构造函数和原型链实现,依赖 prototype 和 this 关键字。函数继承是一种通过函数来创建和扩展对象的方式,通常也被称为构造函数继承。它主要基于函数作为模板创建对象的逻辑。

  • 原理:
    通过调用一个函数(构造函数)来创建一个新对象,然后在构造函数内部添加一些属性和方法。
// 父构造函数
function Animal(name) {
  this.name = name;
}

// 原型方法
Animal.prototype.speak = function() {
  return `${this.name} makes a sound.`;
};

// 子构造函数
function Dog(name, breed) {
  // 继承父类属性
  Animal.call(this, name);
  this.breed = breed;
}

// 继承父类原型方法
// Dog.prototype = new Animal()
Dog.prototype = Object.create(Animal.prototype); 
Dog.prototype.constructor = Dog;

// 子类特有方法
Dog.prototype.bark = function() {
return `${this.name} barks!`;
};
const dog = new Dog("Buddy", "Labrador");
console.log(dog.speak()); // "Buddy makes a sound."
console.log(dog.bark()); // "Buddy barks!"
 

2、类继承(ES6)

 使用 class 关键字和 extends 语法,语法更简洁、直观。类继承是指基于对象原型(prototype)来创建和扩展对象的机制,它使用原型链来实现对象间属性和方法的共享。
  • 原理:
    每个对象都有一个原型(prototype),当访问一个对象的属性或方法时,如果该对象本身没有,就会沿着原型链向上查找,直到找到。
// 父类
class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    return `${this.name} makes a sound.`;
  }
}

// 子类
class Dog extends Animal {
  constructor(name, breed) {
    super(name); // 调用父类构造函数
    this.breed = breed;
  }

  bark() {
    return `${this.name} barks!`;
  }
}

const dog = new Dog("Buddy", "Labrador");
console.log(dog.speak()); // "Buddy makes a sound."
console.log(dog.bark());  // "Buddy barks!"

3、总结

总的来说,函数继承更倾向于创建独立的、有不同属性的对象,而类继承则更适合创建具有共享属性的对象。在现代JavaScript中,类继承(基于ES6 的 class 语法)成为了主流,因为它可以更清晰地表示继承关系,并提供更高级的功能。

二、 实现机制

函数继承

  • 原型链:通过修改 prototype 实现方法共享。
  • 构造函数:使用 call()/apply()/bind() 继承父类属性。
  • 组合继承:结合原型链和构造函数,解决属性和方法的继承问题。

类继承

  • 语法糖:ES6 类本质是基于原型的封装,内部仍使用 prototype
  • extends:自动设置子类的 prototype 指向父类实例。
  • super:用于调用父类的构造函数或方法,避免手动处理原型链。

 

三、 调用父类方法

1、函数继承

需手动通过 Animal.prototype.method.call(this, ...args) 调用。
// 在 Dog 原型方法中调用 Animal 的 speak
Dog.prototype.speakLouder = function() {
  const parentSound = Animal.prototype.speak.call(this);
  return `${parentSound.toUpperCase()}!`;
};

2、类继承

使用 super.method() 直接调用,更简洁。
class Dog extends Animal {
  // ...

  speakLouder() {
    const parentSound = super.speak();
    return `${parentSound.toUpperCase()}!`;
  }
}

 

四、 应用场景

  • 函数继承:适用于需要精细控制原型链的场景,如旧项目维护或需要兼容 ES5 的环境。
  • 类继承:推荐在现代 JavaScript 项目中使用,代码更易读、维护,且支持 ES6+ 特性。

五、总结

维度函数继承类继承
语法复杂度 高,需手动处理原型链 低,语法糖简化继承逻辑
代码可读性 较低,原型链操作易混淆 高,结构清晰
兼容性 支持所有环境 需 ES6+ 或 Babel 编译
灵活性 高,可自定义原型链行为 中,受限于 class 语法
性能 与类继承相近 与函数继承相近

 

posted @ 2025-06-13 10:55  ~小晨晨  阅读(10)  评论(0)    收藏  举报