本文转载自公众号《阅读核心》(ID:AI_Discovery)虽然JavaScript类看起来很正常,但是如果你用一段时间,尤其是以前用过ES5的,你可能会看到原型继承的过程演变为现在的阶级格局。为什么?原型链有什么问题?在我看来,答案是一切正常。但技术社区花了数年时间将类的概念强加到不同的结构和库中,因此ECMA技术委员会决定无论如何都要添加它。这有什么问题吗?在我们已经拥有的原型继承之上添加组合,并决定将其称为类,这反过来又会诱使开发人员认为他们正在处理一种面向对象的语言,而实际上他们并非如此。类只是语法糖。JavaScript不完全支持OOP,因为它从不需要OOP。从表面上看,当前的类布局呈现出一种OPP范式,因为:可以定义基类、分类状态和行为以及特殊的经典语法。可以将一种类型转移到另一种类型。可以定义属性和方法的可用性,包括公共的和私有的。可以为属性定义getter和setter。类继承的方法可以忽略。当然也可以实例化各种类。之所以说类是语法糖,是因为虽然类表面上看起来非常面向对象,但是如果你做一些超出可能范围的事情,比如定义一个涉及另外两个类的类(目前是不可能实现的),你需要使用如下代码://ThehelperfunctionfunctionapplyMixins(derivedCtor,baseCtors){baseCtors.forEach(baseCtor=>{Object.getOwnPropertyNames(baseCtor.prototype).forEach(name=>{letdescriptor=Object.getOwnPropertyDescriptor(baseCtor.prototype,name)Object.defineProperty(derivedCtor.prototype,name,descriptor);});});}//父类classA{methodA(){console.log("A")}}classB{methodB(){console.log("B")}}//ThechildclassclassC{}//使用mixinsapplyMixins(C,[A,B])leto=newC()o.methodA()o.methodB()我们需要这样做,因为JS无法编辑:classA{methodA(){console.log("A")}}classB{methodB(){console.log("B")}}classCextendsA,B{}在某些情况下,这种行为可能会派上用场,JavaScript人员创建了上面的代码片段,我只是删除了额外的代码以使其与纯JS一起工作。但是示例代码的重要信息应该是applyMixins函数。即使没有完全理解它的作用,它也被用来评估各种类的原型属性以复制和重新分配方法和属性。这就是发现的所有证据:类只不过是已证明的原型继承模型之上的语法糖。这是否意味着应该停课?并不真地。了解这一点很重要,如果您需要突破类可以做什么和不能做什么的界限,那么您将不得不处理原型来做到这一点。JavaScript的OOP模型遗漏了什么?如果现在的OOP模型并不完美,只是原型继承的抽象,那我们还缺少什么?是什么让JS成为真正的OOP?要回答这个问题,首先要看JavaScript的功能,这门语言背后的团队肯定会发明一些将JavaScript转换为JS的东西,将JavaScript推向极限。这反过来又限制了它们的能力,但是,启动OOP愿望清单的一个好方法是查看它们与OOP相关的功能。您会立即注意到一个警告:JavaScript中当前缺少的一些OOP结构具有内置类型检查,并且在动态类型语言中没有实际意义,可能是因为它们尚未添加。接口这些是有助于定义类应符合的API的重要结构。接口的主要好处之一(在无类型JS中可能会丢失)是您可以为实现相同接口的任何类定义一个变量,并安全地调用其上的任何方法。interfaceAnimal{speak()}classDogimplementsAnimal{speak(){console.log("Woof!")}}classCatimplementsAnimal{speak(){console.log("Meau!")}}classHumanimplementsAnimal{speak(){console.log("Heydude,what'sup?")}}//ifwehadInterfacesinJSwecouldsafelydo:letobjects=[newDog(),newCat(),newHuman()]objects.forEach(o=>o.speak())这在普通JS中是做不到的它。当然可以通过定义一个speak方法并重写它的类来实现同样的目的。但话又说回来,也可以使用任何其他强大的OOP语言来执行此操作,并具有更清晰、更简洁的界面。抽象类每当我尝试使用代码进行完整的OOP时,我肯定会想念JS中的抽象类。抽象类定义和实现方法,但从不实例化。这是一种对可以扩展但不能直接使用的常见行为进行分组的方法。它绝对可以在当前的JS领域内实现,而不会造成太多干扰。静态多态性静态多态性允许我们在同一个类中多次定义相同的方法,但具有不同的签名。换句话说,重复名称,但确保它接收不同的参数。现在我们有使用JS的剩余参数,这允许我们有任意数字,但是,这也意味着必须向方法添加额外的代码来处理这种动态级别。相反,如果可以更清楚地区分方法签名,则可以将相同行为的不同风格直接封装到不同的方法中。上面的版本是无效的JS,但是它的代码更干净,所以它需要更少的认知负荷来进行心理分析。但是,下面的版本是完全有效的。它需要一些思想复合,并围绕它编写更多代码,因为它不仅会记录(这应该是它的唯一目的),而且会尝试根据提供的参数决定如何记录。静态多态性通常通过查看方法中接收的参数类型来实现。但是,我们知道由于JS的工作方式,这是不可能的。受保护的属性和方法已经具有公共可见性,并且很快获得了方法和属性的私有可见性。下一步应该是添加受保护的可见性,如果您想拥有适当的OOP体验,这三者都是必需的。受保护的属性和方法只能从类内部或其子类之一访问(与私有可见性相反,私有可见性仅限于父类)。我一直在努力将JS称为OOP语言,在我找到一种无需引用原型链即可处理类内部的方法之前,我不会继续尝试。为什么他们不能继续扩展原型继承模型而不是给我们这个廉价的类版本?这是一个长期存在的问题。现在,我想对添加的语法糖表示感谢,并在未来留意新的基于oop的功能。
