JavaScript的原型概念
为了本文的目的,最好先讨论JavaScript中的原型概念。
在JavaScript中,所有对象都从原型继承属性和方法。让我们考虑以下原型示例:
- functionVehicle(vinNumber,manufacturer,productionDate,fuelType) {
- this.manufacturer=manufacturer;
- this.vinNumber=vinNumber;
- this.productionDate=productionDate;
- this.fuelType=fuelType;
- }
- Vehicle.prototype.vehicleInformation=function() {
- varproductionDate=newDate(this.productionDate*1000);
- varmonths=['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
- varyear=productionDate.getFullYear();
- varmonth=months[productionDate.getMonth()];
- varday=productionDate.getDate();
- varfriendlyDate=month+' '+day+', '+year;
- returnthis.manufacturer+' vehicle with VIN Number = '+this.vinNumber+' was produced on '+friendlyDate+' using a fuel type of '+this.fuelType;
- }
作为此代码的结果,有一个Vehicle对象,可以使用以下代码创建新实例:
- letrogue=newVehicle('5N1FD4YXN11111111','Nissan',1389675600,'gasoline');
有了这些信息,vehicleInformation()函数可以使用以下方法调用:
- alert(rogue.vehicleInformation());
这将生成一个警报对话框,其中包含以下消息:
日产汽车VIN号为5N1FD4YXN11111111,于2014年1月14日使用一种燃料类型的汽油生产
如人们所料,第二个原型名为SportUtilityVehicle可以引入以进一步定义给定类型的车辆:
- functionSportUtilityVehicle(vinNumber,manufacturer,productionDate,fuelType,drivetrain) {
- Vehicle.call(this,vinNumber,manufacturer,productionDate,fuelType);
- this.drivetrain=drivetrain;
- }
- 现在,我们可以SportUtilityVehicle而不是简单的Vehicle.
- letrogue=newSportUtilityVehicle('5N1FD4YXN11111111','Nissan',1389675600,'gasoline','AWD');
- 我们还可以使用SportUtilityVehicle原型:
- SportUtilityVehicle.prototype.vehicleInformation=function() {
- returnthis.manufacturer+' vehicle with VIN Number = '+this.vinNumber+' utilizes drivetrain = '+this.drivetrain+' and runs on '+this.fuelType;
- }
现在,当vehicleInformation()函数使用以下方法调用:
- alert(rogue.vehicleInformation());
将出现一个警报对话框,其中包含以下消息:
“VIN编号=5N1FD4YXN11111111的日产汽车采用传动系=AWS,以汽油运行”
JavaScript类
从ECMAScript 2015(2015年6月作为第6版发布)开始,JavaScript引入了类的概念。虽然这可能引起使用Java、C#和C++等语言的开发人员的兴趣,但引入类选项的目的是允许使用更简单、更简洁的语法创建类。事实上,文档还指出,类只是“语法糖”,以使开发人员更容易。
将前面的示例从原型转换为类,如下所示:
classVehicle{
constructor(vinNumber,manufacturer,productionDate,fuelType) {
this.manufacturer=manufacturer;
this.vinNumber=vinNumber;
this.productionDate=productionDate;
this.fuelType=fuelType;
}
vehicleInformation() {
varproductionDate=newDate(this.productionDate*1000);
varmonths=['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
varyear=productionDate.getFullYear();
varmonth=months[productionDate.getMonth()];
varday=productionDate.getDate();
varfriendlyDate=month+' '+day+', '+year;
returnthis.manufacturer+' vehicle with VIN Number = '+this.vinNumber+' was produced on '+friendlyDate+' using a fuel type of '+this.fuelType;
}
}
classSportUtilityVehicleextendsVehicle{
constructor(vinNumber,manufacturer,productionDate,fuelType,drivetrain) {
super(vinNumber,manufacturer,productionDate,fuelType);
this.drivetrain=drivetrain;
}
vehicleInformation() {
returnthis.manufacturer+' vehicle with VIN Number = '+this.vinNumber+' utilizes drivetrain = '+this.drivetrain+' and runs on '+this.fuelType;
}
}
如果我们需要将getter和setter添加到SportUtilityVehicle类时,可以按如下所示更新该类:
classSportUtilityVehicleextendsVehicle{
constructor(vinNumber,manufacturer,productionDate,fuelType,drivetrain) {
super(vinNumber,manufacturer,productionDate,fuelType);
this.drivetrain=drivetrain;
}
vehicleInformation() {
returnthis.manufacturer+' vehicle with VIN Number = '+this.vinNumber+' utilizes drivetrain = '+this.drivetrain+' and runs on '+this.fuelType;
}
getdrivetrain() {
returnthis._drivetrain;
}
setdrivetrain(newDrivetrain) {
this._drivetrain=newDrivetrain;
}
}
如您所见,语法类似于Java或C#等语言。类方法还允许属于原型链的函数和属性不引用Object.Prototype语法。一个要求是构造函数总是被称为“构造函数”。
JavaScriptClass V原型
如前所述,JavaScript中的类只是语法上的糖,可以使在JavaScript中工作的特性开发人员更加容易。虽然这种方法允许对来自Java、C#或C++等语言的人进行更普遍的设计,但许多Javascript纯粹主义者建议根本不要使用类。
事实上,迈克尔·克拉斯诺夫在“请停止使用JavaScript中的类“条款:
约束力问题。当类构造函数密切处理这个关键字时,它可能会引入潜在的绑定问题,特别是当您试图将类方法作为回调传递给外部例程时。
Michael继续给出了避免使用Javascript类的其他四个原因,但是类选项的拥护者很快就减轻了他的想法。
从2021年开始,我一直坚持以下任何IT专业人员的使命声明:
“把你的时间集中在交付特性/功能上,它扩展了你的知识产权的价值。将框架、产品和服务用于其他一切。”
在JavaScript中使用类或原型时,我觉得这是支持和维护代码库的团队应该做出的决定。如果他们的舒适度水平没有问题,遵循原型方法,那么他们应该相应地设计他们的组件。但是,如果偏好是利用类的概念,那么团队中的开发人员应该了解上面提到的绑定挑战,但是应该继续前进,保持在他们的舒适范围内。
对闪电Web组件的影响
Salesforce几年前引入了闪电网络组件(LightingWeb Components,LWC),我在“Salesforce提供JavaScript编程模型近三年后,我发现自己正在谈论使用Salesforce开发人员使用类和原型方法的影响。
快速的答案是..。无所谓。Salesforce允许闪电Web组件利用原型或类。JavaScript的典型继承模型是通过原型实现的。但是为了吸引习惯于古典继承的开发人员,有一种语法糖可以帮助开发人员通过使用一种看起来非常类似于古典继承的方法来实现原型继承。
因此,当涉及到LWC时--因为LWC已经为您构建了一个非常棒的基类组件供您扩展--这一切都是关于继承的--您也可以利用这个语法糖。
您不需要担心原型继承,即使这一切都发生在幕后。只要做古典遗产的事,你就金碧辉煌了。
下面是一个例子,说明这可能是什么样子:
import{LightningElement}from'lwc';
exportdefaultclassVehicleComponentextendsLightningElement{
// properties go here
vehicleInformation() {
returnthis.manufacturer+' vehicle with VIN Number = '+this.vinNumber+' utilizes drivetrain = '+this.drivetrain+' and runs on '+this.fuelType;
}
}
看见?LWC--知道JavaScript为您提供了这种语法糖--使您变得非常容易。
结语
我要承认,JavaScript不是我大部分时间用于开发特性的语言。除了使用Node.js进行角度和小范围的客户端开发之外,我作为服务开发人员的主要工作通常集中在其他语言选项上。
同时,使用类方法而不是原型方法提供了与Java、C#和C++开发人员类似的桥梁。虽然这里没有正确的答案,但是理解类和原型在JavaScript中的工作方式是很重要的。