当前位置:  首页>> 技术小册>> JavaScript面试指南

JavaScript 是一门基于原型的语言,因此它的继承方式也是通过原型链来实现的。通过原型链,一个对象可以从另一个对象那里继承属性和方法。

在 JavaScript 中,有以下几种方式实现继承:

原型链继承
原型链继承是 JavaScript 中最常见的继承方式,它通过将子类的原型指向父类的实例来实现继承。子类可以访问父类原型中的属性和方法。

  1. function Animal(name) {
  2. this.name = name;
  3. }
  4. Animal.prototype.eat = function() {
  5. console.log(this.name + " is eating.");
  6. };
  7. function Dog(name) {
  8. this.bark = function() {
  9. console.log("Woof!");
  10. };
  11. }
  12. Dog.prototype = new Animal();
  13. var dog1 = new Dog("Max");
  14. dog1.eat(); // Output: "Max is eating."
  15. dog1.bark(); // Output: "Woof!"

在上面的例子中,我们定义了一个 Animal 构造函数和一个 Dog 构造函数。我们将 Dog 的原型设置为 Animal 的一个实例,这样 Dog 的实例就可以访问 Animal 原型中的 eat 方法。

构造函数继承
构造函数继承通过在子类的构造函数中调用父类的构造函数来实现继承。这种方式可以继承父类的实例属性,但是无法继承父类的原型属性和方法。

  1. function Animal(name) {
  2. this.name = name;
  3. }
  4. Animal.prototype.eat = function() {
  5. console.log(this.name + " is eating.");
  6. };
  7. function Dog(name) {
  8. Animal.call(this, name);
  9. this.bark = function() {
  10. console.log("Woof!");
  11. };
  12. }
  13. var dog1 = new Dog("Max");
  14. dog1.eat(); // Output: TypeError: dog1.eat is not a function
  15. dog1.bark(); // Output: "Woof!"

在上面的例子中,我们定义了一个 Animal 构造函数和一个 Dog 构造函数。在 Dog 的构造函数中,我们使用 call 方法调用了 Animal 的构造函数,并传入了 this 参数,这样 Dog 的实例就可以继承 Animal 的实例属性。

组合继承
组合继承是将原型链继承和构造函数继承结合起来的一种方式。它通过将子类的原型设置为父类的实例来实现原型链继承,同时在子类的构造函数中调用父类的构造函数来实现构造函数继承。

  1. function Animal(name) {
  2. this.name = name;
  3. }
  4. Animal.prototype.eat = function() {
  5. console.log(this.name + " is eating.");
  6. };
  7. function Dog(name) {
  8. Animal.call(this, name);
  9. }
  10. Dog.prototype = new Animal();
  11. var dog1 = new Dog("Max");
  12. dog1.eat(); // Output: "Max is eating."

在上面的例子中,我们定义了一个 Animal 构造函数和一个 Dog 构造函数。在 Dog 的构造函数中,我们使用 Animal.call(this, name) 调用了 Animal 的构造函数,并传入了 this 参数,这样 Dog 的实例就可以继承 Animal 的实例属性。同时,我们将 Dog 的原型设置为 Animal 的一个实例,这样 Dog 的实例也可以访问 Animal 原型中的方法。这样一来,Dog 的实例就同时继承了父类的实例属性和原型属性。

需要注意的是,使用组合继承的方式会调用两次父类的构造函数,一次在子类的构造函数中,一次在将子类的原型设置为父类实例时。因此,这种方式可能会导致性能问题。

原型式继承
原型式继承是通过创建一个空对象并将其原型设置为要继承的对象来实现继承的。这种方式可以快速地创建对象,但是无法解决父子之间的引用问题。

  1. var animal = {
  2. name: "",
  3. eat: function() {
  4. console.log(this.name + " is eating.");
  5. }
  6. };
  7. var dog = Object.create(animal);
  8. dog.bark = function() {
  9. console.log("Woof!");
  10. };
  11. dog.name = "Max";
  12. dog.eat(); // Output: "Max is eating."
  13. dog.bark(); // Output: "Woof!"

在上面的例子中,我们创建了一个 animal 对象,然后通过 Object.create 方法将其原型设置为 animal。接着,我们定义了一个 dog 对象,并在其中添加了一个 bark 方法。最后,我们将 dog 的 name 属性设置为 Max,并调用 dog 的 eat 方法和 bark 方法。

寄生式继承
寄生式继承是在原型式继承的基础上,通过在一个新对象上添加方法并返回该对象来实现继承的。这种方式可以在不修改原对象的情况下对其进行扩展。

  1. var animal = {
  2. name: "",
  3. eat: function() {
  4. console.log(this.name + " is eating.");
  5. }
  6. };
  7. function createDog(name) {
  8. var dog = Object.create(animal);
  9. dog.name = name;
  10. dog.bark = function() {
  11. console.log("Woof!");
  12. };
  13. return dog;
  14. }
  15. var dog1 = createDog("Max");
  16. dog1.eat(); // Output: "Max is eating."
  17. dog1.bark(); // Output: "Woof!"

在上面的例子中,我们定义了一个 animal 对象,然后通过 createDog 函数实现了一个寄生式继承。在 createDog 函数中,我们首先通过 Object.create 方法创建了一个新对象 dog,然后在 dog 对象中添加了一个 bark 方法,
并将name 属性设置为传入的 name 值。最后,返回该对象,即可实现继承。

需要注意的是,寄生式继承与原型式继承一样,都无法解决父子之间的引用问题。

寄生组合式继承
寄生组合式继承是继承中的最佳实践,它通过组合继承和寄生式继承的方式来实现继承,并且避免了组合继承中的性能问题和寄生式继承中的引用问题。

  1. function Animal(name) {
  2. this.name = name;
  3. }
  4. Animal.prototype.eat = function() {
  5. console.log(this.name + " is eating.");
  6. };
  7. function Dog(name) {
  8. Animal.call(this, name);
  9. }
  10. (function() {
  11. // 创建一个空对象作为中介
  12. var Super = function() {};
  13. Super.prototype = Animal.prototype;
  14. // 将中介对象的实例作为子类的原型
  15. Dog.prototype = new Super();
  16. })();
  17. Dog.prototype.bark = function() {
  18. console.log("Woof!");
  19. };
  20. var dog1 = new Dog("Max");
  21. dog1.eat(); // Output: "Max is eating."
  22. dog1.bark(); // Output: "Woof!"

在上面的例子中,我们首先定义了 Animal 和 Dog 两个构造函数。在 Dog 的构造函数中,我们通过 Animal.call(this, name) 调用了 Animal 的构造函数,并传入了 this 参数,这样 Dog 的实例就可以继承 Animal 的实例属性。

接着,我们使用了一个自执行函数来实现寄生式继承。在该函数中,我们创建了一个空对象 Super,并将 Animal.prototype 赋值给了 Super.prototype。这样,Super 对象就成为了 Animal.prototype 的一个中介对象,可以将 Dog 的原型设置为 Super 的一个实例,以避免调用两次父类的构造函数。

最后,我们在 Dog 的原型中添加了一个 bark 方法,并创建了一个 dog1 实例,可以发现 dog1 实例可以同时访问 Animal 和 Dog 的方法和属性,且避免了调用两次父类的构造函数和引用问题。


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