多年来,OOP(面向对象编程)一直是软件工程的事实标准。类、多态性、继承和封装的概念主导并彻底改变了开发过程。但一切都有有效期,包括编程示例。在本文中,我将讨论为什么首先引入类,为什么在JavaScript中使用类是一个坏主意,以及一些替代方案。ES6之前的类尽管自ES6(ECMAScript2015)以来class关键字就被添加到JavaScript中,但人们仍在使用类。实现的方法是构造函数和原型委托。为了准确说明我的意思,我将在ES5和ES6环境中实现相同的类。考虑继承自Car的Car和SportsCar类。两者都有制造(make)、模型(model)属性和启动方法(start),但SportsCar还有涡轮增压(turbocharged)属性并覆盖启动方法(start)。//“类”声明函数Car(make,model){this.make=make;this.model=model;}//启动方法Car.prototype.start=function(){console.log('vroom');}//重写toString方法Car.prototype.toString=function(){console.log('Car-'+this.make+'-'+this.model);}//继承实例functionSportsCar(make,model,turbocharged){Car.call(this,make,model);this.turbocharged=turbocharged;}//实际继承逻辑SportsCar.prototype=Object.create(Car.prototype);SportsCarSportsCar.prototype.constructor=SportsCar;//覆盖开始methodSportsCar.prototype.start=function(){console.log('VROOOOM');}//现在测试类classesvarcar=newCar('Nissan','Sunny');car.start();//vroomconsole.log(car.make);//NissanvarsportsCar=newSportsCar('Subaru','BRZ',true);sportsCar.start();//VROOOOMconsole.log(car.turbocharged);//true你可能已经猜到了,Car(第2页)和SportsCar(第18行)函数是构造函数。使用this关键字来定义属性,并使用new来创建对象本身。如果你不熟悉原型,这是一个特殊的属性,每个JS对象都必须将通用行为委托给它。例如,数组对象的原型有您可能熟悉的函数:map、forEach、find等。字符串原型有函数replace、substr等。在第33行创建Car对象后,其属性和方法可以访问。从第34行开始的调用产生以下结果:JS引擎向car对象询问带有键start的值。该对象响应它没有这样的值。JS引擎向car.prototype对象询问以键start开头的值。car.prototype返回JS引擎立即执行的启动函数。访问make和model属性是类似的,除了它们是直接在汽车对象上定义的,而不是原型上。继承有点棘手,它在第24-25行处理。这里最重要的函数是Object.create函数,它接受一个对象并返回一个全新的对象,其原型设置为作为参数传递的对象。现在,如果JS引擎在sportsCar对象或sportsCar.prototype上找不到值,它将查找sportsCar.prototype.prototype,这是Car对象的原型。ES6Class关键字随着2015年ES6的发布,期待已久的class关键字出现在JavaScript中。这样做是为了响应社区的多项请求,因为人们对来自面向对象的语言感到不舒服。但是他们忽略了一个重要的问题。JavaScript不知道什么是类JavaScript不是一种面向对象的语言,它不是设计成这样的,而且类的概念绝对不适用于它。虽然JS中的一切都是对象,但这些对象与Java或C#中的对象不同。在JS中,对象只是具有某种复杂查找过程的Map数据结构。就是这样。当我说一切都是对象时,我是认真的:即使是函数也是对象。您可以查看以下代码片段:functioniAmAnObject(){}console.log(iAmAnObject.name);//iAmAnObjectconsole.log(Object.keys(iAmAnObject));//Array[]class关键字有效吗?很高兴你问。您还记得前面的Car和SportsCar示例吗?好吧,class关键字只是最重要的语法糖。换句话说,类在概念上产生相同的代码,并且仅用于美观和可读性目的。正如我之前承诺的,这里是ES6中这些相同类的示例:}toString(){console.log(`Car-${this.make}-${this.model}`);}}classSportsCarextendsCar{constructor(make,model,turbocharged){super(make,model);this.turbocharged=turbocharged;}start(){console.log('VROOOOM');}}//实际用法不变varcar=newCar('Nissan','Sunny');car.start();//vroomconsole.log(car.make);//NissanvarsportsCar=newSportsCar('Subaru','BRZ',true);sportsCar.start();//VROOOOMconsole.log(car.turbocharged);//true这些例子是相同,并产生相同的结果,有趣的是,它们在幕后生成(几乎)相同的代码。为什么不?到目前为止,您应该了解JS中有哪些类以及它们是如何工作的。现在,有了所有这些知识,我可以解释为什么在JS中使用类是一个坏主意。绑定问题。由于类构造函数与this关键字紧密合作,它可能会引入潜在的绑定问题,尤其是当您尝试将类方法作为回调传递给外部例程时(你好,React开发人员)。性能问题。由于类的实现,它们在运行时很难优化。虽然我们目前享受高性能机器,但摩尔定律正在消退的事实可能会改变这一切。私有变量。首先,私有变量的最大优点和主要原因之一是JS中不存在类。等级森严。类直接引入了从上到下的顺序,使得更改更难实现,这在大多数JS应用程序中是不可接受的。因为React团队会告诉你不要这样做。虽然他们还没有明确地弃用基于类的组件,但很可能在不久的将来就会弃用。所有这些问题都可以通过JS对象和原型委托来缓解。JS提供了很多类可以做的事情,但大多数开发人员对此视而不见。要想真正掌握JS,就需要接受它的哲学,摆脱教条式的阶级思维。
