面试题答案
一键面试联系
- 本质相同:在JavaScript中,class本质上是基于原型的语法糖。无论是通过class还是直接基于prototype创建对象,最终都是利用原型链实现继承。例如:
// 基于原型创建对象
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
console.log(this.name + ' makes a sound.');
};
// 基于class创建对象
class Dog extends Animal {
constructor(name, breed) {
super(name);
this.breed = breed;
}
bark() {
console.log(this.name + ' barks.');
}
}
const dog = new Dog('Buddy', 'Golden Retriever');
dog.bark();
dog.speak();
这里Dog
类继承自Animal
,Dog
的实例dog
可以访问Animal
原型上的speak
方法,无论是class
语法还是原型写法,都是通过原型链实现这种继承关系。
区别
- 语法复杂度:
- class:语法更简洁、直观,更符合传统面向对象编程的习惯。比如上面
Dog
类定义时,使用extends
关键字明确表示继承关系,constructor
定义构造函数,整体结构清晰。 - prototype:语法相对复杂,需要手动在构造函数的原型上添加属性和方法。例如
Animal.prototype.speak = function() {... }
这种写法,对于初学者理解和编写代码的难度相对较大。
- class:语法更简洁、直观,更符合传统面向对象编程的习惯。比如上面
- 函数声明方式:
- class:类的方法默认是不可枚举的。比如在上面
Dog
类中的bark
方法,使用Object.keys(Dog.prototype)
无法获取到bark
方法名。 - prototype:通过原型添加的方法默认是可枚举的。如
Object.keys(Animal.prototype)
会包含speak
方法名。
- class:类的方法默认是不可枚举的。比如在上面
- 构造函数的处理:
- class:必须使用
new
关键字调用构造函数,如果不使用new
,会抛出错误。例如let cat = Dog('Tom', 'Siamese');
会报错。 - prototype:构造函数既可以使用
new
调用,也可能在某些错误使用场景下不使用new
调用,且不会直接报错(虽然结果可能不符合预期)。例如function Cat(name) { this.name = name; }
,let cat = Cat('Tom');
不会报错,但cat
可能不是预期的Cat
实例对象。
- class:必须使用