面试题答案
一键面试底层实现机制差异
- 原型链构建
- 基于 prototype 的继承:通过
Object.create()
方法或者直接操作prototype
属性来构建原型链。例如:
- 基于 prototype 的继承:通过
function Animal() {
this.species = 'animal';
}
Animal.prototype.speak = function() {
console.log('I am an animal');
};
function Dog() {
Animal.call(this);
this.name = 'dog';
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function() {
console.log('Woof!');
};
这里 Dog.prototype
是通过 Object.create(Animal.prototype)
创建,从而建立起 Dog
到 Animal
的原型链。
- ES6 类继承:使用 class
和 extends
关键字,内部仍然基于原型链实现,但语法糖简化了操作。例如:
class Animal {
constructor() {
this.species = 'animal';
}
speak() {
console.log('I am an animal');
}
}
class Dog extends Animal {
constructor() {
super();
this.name = 'dog';
}
bark() {
console.log('Woof!');
}
}
class
语法在底层同样构建原型链,Dog.prototype
会继承 Animal.prototype
,super()
用于调用父类构造函数,正确设置 this
指向等。
2. 方法和属性的继承过程
- 基于 prototype 的继承:构造函数中的属性通过 call
或 apply
方法在子类构造函数中调用父类构造函数来继承,方法则通过原型链查找。例如上面 Dog
继承 Animal
,species
属性通过 Animal.call(this)
继承,speak
方法通过原型链查找。
- ES6 类继承:属性继承也是通过 super()
调用父类构造函数实现,方法同样基于原型链查找。但 class
语法更直观,super
关键字明确表示对父类的引用,如在 Dog
类中调用 super()
初始化父类属性。
使用场景不同
- 基于 prototype 的继承
- 场景:适用于对 JavaScript 原型机制有深入理解,需要高度定制化继承行为的场景。例如在一些需要手动优化原型链,或者与旧版 JavaScript 代码紧密结合的项目中。比如编写一个高度可定制的 JavaScript 库,开发者可能希望手动控制原型链上属性和方法的继承与覆盖。
- ES6 类继承
- 场景:适用于大多数现代 JavaScript 项目,尤其是注重代码可读性和简洁性的场景。例如在开发大型 Web 应用程序时,团队成员可能更熟悉面向对象的语法,
class
语法更符合这种思维模式,使代码结构更清晰,易于维护和扩展。如构建一个基于 React 的组件库,使用class
继承可以使组件之间的关系更直观。
- 场景:适用于大多数现代 JavaScript 项目,尤其是注重代码可读性和简洁性的场景。例如在开发大型 Web 应用程序时,团队成员可能更熟悉面向对象的语法,