MST

星途 面试题库

面试题:JavaScript 中 prototype 特性对函数继承的影响

在 JavaScript 中,使用 prototype 实现函数继承有哪些关键要点?请通过代码示例展示不同的继承方式,并分析其优缺点。
23.1万 热度难度
编程语言JavaScript

知识考点

AI 面试

面试题答案

一键面试

关键要点

  1. 原型链的构建:通过将子类的原型对象设置为父类的实例,从而形成原型链,使得子类可以访问父类原型上的属性和方法。
  2. 借用构造函数:在子类构造函数内部通过 callapply 方法调用父类构造函数,以继承父类的实例属性。

不同继承方式及代码示例

  1. 原型链继承
function Animal(name) {
    this.name = name;
}
Animal.prototype.speak = function() {
    console.log(this.name +'makes a sound.');
};
function Dog(name, breed) {
    this.breed = breed;
}
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;
let myDog = new Dog('Buddy', 'Golden Retriever');
myDog.speak(); 

优点:简单直观,易于理解和实现,子类可以共享父类原型上的属性和方法,节省内存。 缺点:无法向父类构造函数传递参数;所有子类实例共享父类实例属性,一个实例对该属性的修改会影响其他实例。

  1. 借用构造函数继承
function Animal(name) {
    this.name = name;
}
function Dog(name, breed) {
    Animal.call(this, name);
    this.breed = breed;
}
let myDog = new Dog('Buddy', 'Golden Retriever');
console.log(myDog.name); 

优点:可以向父类构造函数传递参数,每个子类实例都有自己独立的属性,不会相互影响。 缺点:子类无法继承父类原型上的方法,必须在每个子类构造函数中重新定义相同的方法,导致代码冗余。

  1. 组合继承
function Animal(name) {
    this.name = name;
}
Animal.prototype.speak = function() {
    console.log(this.name +'makes a sound.');
};
function Dog(name, breed) {
    Animal.call(this, name);
    this.breed = breed;
}
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;
let myDog = new Dog('Buddy', 'Golden Retriever');
myDog.speak(); 

优点:融合了原型链继承和借用构造函数继承的优点,既能继承父类原型上的方法,又能拥有自己独立的属性。 缺点:父类构造函数会被调用两次,一次是在创建子类原型时(new Animal()),一次是在子类构造函数内部(Animal.call(this, name)),导致不必要的开销。

  1. 寄生组合继承
function Animal(name) {
    this.name = name;
}
Animal.prototype.speak = function() {
    console.log(this.name +'makes a sound.');
};
function Dog(name, breed) {
    Animal.call(this, name);
    this.breed = breed;
}
function inheritPrototype(subType, superType) {
    let prototype = Object.create(superType.prototype);
    prototype.constructor = subType;
    subType.prototype = prototype;
}
inheritPrototype(Dog, Animal);
let myDog = new Dog('Buddy', 'Golden Retriever');
myDog.speak(); 

优点:修复了组合继承中父类构造函数被调用两次的问题,高效地实现了继承。既保证了原型链的正确性,又能正常向父类构造函数传递参数,同时避免了不必要的开销。 缺点:实现相对复杂,需要额外的辅助函数来处理原型链的构建。