本文将介绍在 JavaScript
何时使用class
以及何时使用prototype
。
首先先介绍一下prototype
的概念,在Javascript
中,所有的对象都从原型中继承属性和方法。
function Car(brand, vinNumber) {
this.brand = brand;
this.vinNumber = vinNumber;
}
Car.prototype.carInfo = function() {
return {
brand: this.brand,
vinNumber: this.vinNumber
}
}
在创建了上面的Car
对象后,就可以使用以下的方式创建一个实例:
const byd = new Car('byd', 'qwuiqbasunqwidn123123');
创建了一个byd
实例后,就可以调用carInfo
这个方法:
console.log(byd.carInfo());
在这种情况下我们还可以通过call
或者apaply
方法来扩展Car
对象来实现不同类型的车辆。
function SportUtilityCar(brand, vinNumber, drivetrain) {
Car.call(this, brand, vinNumber);
this.drivetrain = drivetrain;
}
现在,我们就可以创建一个SportUtilityCar
的实例而非Car
。
const byd = new SportUtilityCar('byd', 'qwuiqbasunqwidn123123', 'AWD');
而且我们还可以通过原型为SportUtilityCar
定义一个新版本的carInfo
方法。
SportUtilityCar.prototype.carInfo = function() {
return {
brand: this.brand,
vinNumber: this.vinNumber,
drivetrain: this.drivetrain
}
}
调用新版本的carInfo
方法:
console.log(byd.carInfo());
在ECMAScript 2015
中js
推出了class
这个概念。引入class
的目标是允许使用更简单、更干净的语法创建类。事实上,class
只是一个“语法糖”,以使开发人员能更容易编写代码。
将前面用prototype
实现的代码转换成class
。
class Car {
constructor(brand, vinNumber) {
this.brand = brand;
this.vinNumber = vinNumber;
}
carInfo() {
return {
brand: this.brand,
vinNumber: this.vinNumber
}
}
}
class SportUtilityCar extends Car {
constructor(brand, vinNumber, drivetrain) {
super(brand, vinNumber);
this.drivetrain = drivetrain;
}
carInfo() {
return {
brand: this.brand,
vinNumber: this.vinNumber,
drivetrain: this.drivetrain
}
}
}
如果我们需要在类中添加 getter
和 setter
,可以通过以下写法。
class SportUtilityCar extends Car {
constructor(brand, vinNumber, drivetrain) {
super(brand, vinNumber);
this.drivetrain = drivetrain;
}
carInfo() {
return {
brand: this.brand,
vinNumber: this.vinNumber,
drivetrain: this.drivetrain
}
}
get drivetrain() {
return this._drivetrain;
}
set drivetrain(newDrivetrain) {
this._drivetrain = newDrivetrain;
}
}
class
的语法类似于 Java
或 C#
等语言。class
方法允许不通过 Object.prototype
语法而为原型链添加属性和方法。
如上所述,JavaScript
中的类只是语法糖,虽然这种方法允许那些来自Java
,C#
或C++
等语言的人也可以更加快速的上手javascript
,但许多Javascript
纯粹主义者建议不要使用类。
例如,Michael Krasnov
在Please stop using classes in JavaScript文章中提到一个问题:
Binding issues. As class constructor functions deal closely with this keyword, it can introduce potential binding issues, especially if you try to pass your class method as a callback to an external routine.
翻译: 绑定问题。由于类构造函数密切处理此关键字,因此可能会引入潜在的绑定问题,尤其是在尝试将类方法作为回调传递给外部程序时。
当谈到在 JavaScript
中使用类或原型时,我觉得这是一个应该由支持和维护代码库的团队做出的决定。如果他们习惯于原型写法,那么就应该合理设计他们的组件。但是,如果偏好是利用class
概念,则该团队的开发人员应该了解上述绑定挑战,但应该继续保持在他们的编程习惯。