想象我们正在建立一个玩家生活在动物世界中的游戏。有些是朋友,有些是敌对的(像我这样的狗人可能会说所有猫都是敌对的生物)。我们可以创建一个hostileanimal,它可以扩展动物,以充当猫的基础。在某个时候,我们决定添加旨在伤害人类的机器人。我们要做的第一件事是创建机器人类。现在,我们有两个具有相似属性的类。例如,hostileanimal和机器人都可以攻击()。
>
>如果我们可以以某种方式在单独的类或对象中定义敌意,请说敌对,我们可以将其重用为CAT作为机器人。我们可以以各种方式做到这一点。
>多重继承
是某些经典的OOP语言支持的功能。顾名思义,它使我们能够创建一个从多个基类继承的类。查看CAT类在以下Python代码中如何扩展多个基类:and接口
是(键入)经典OOP语言中的常见功能。它允许我们定义类应包含的方法(有时是属性)。如果该课程没有,编译器将引起错误。如果CAT没有攻击()或walk()方法:<span>class Animal(object): </span> <span>def walk(self): </span> <span># ... </span> <span>class Hostile(object): </span> <span>def attack(self, target): </span> <span># ... </span> <span>class Dog(Animal): </span> <span># ... </span> <span>class Cat(Animal, Hostile): </span> <span># ... </span> dave <span>= Cat(); </span>dave<span>.walk(); </span>dave<span>.attack(target); </span>
a recap:es2015类语法
>如果您没有机会参加ES2015课程或觉得自己对它们的了解不足,请务必阅读Jeff Mott面向对象的JavaScript - 在继续之前深入研究ES6课程。 > 简而言之:<span>interface Hostile { </span> <span>attack(); </span><span>} </span> <span>class Animal { </span> <span>walk(); </span><span>} </span> <span>class Dog extends Animal { </span> <span>// ... </span><span>} </span> <span>class Cat extends Animal implements Hostile { </span> <span>attack() { </span> <span>// ... </span> <span>} </span><span>} </span>
的类
类foo扩展bar {...}描述了一个foo的类,该类扩展了另一个类,bar>
在类块中,我们可以定义该类的属性。在本文中,我们只需要了解构造函数和方法:级语法主要是JavaScript原型模型上的句法糖。它不是创建类,而是创建一个函数构造函数:
>如前所述,这种方法依赖于继承。要继承多个类,我们将需要多个继承或混合素。
<span>class Animal { </span> <span>// ... </span><span>} </span> <span>trait Hostile { </span> <span>// ... </span><span>} </span> <span>class Dog extends Animal { </span> <span>// ... </span><span>} </span> <span>class Cat extends Animal { </span> <span>use Hostile; </span> <span>// ... </span><span>} </span> <span>class Robot { </span> <span>use Hostile; </span> <span>// ... </span><span>} </span>>另一种方法是编写一个实用程序函数,该函数在定义后验证类。可以在等待时找到一个例子,JavaScript确实支持多个继承!由Andrea Giammarchi。请参阅“基本对象”部分。
>探索应用多种继承和混合素的各种方法的时间。以下所有检查的策略均可在GitHub上获得。
> ES2015前,我们使用原型来继承。所有功能都有一个原型属性。使用新的myFunction()创建实例时,将原型复制到实例中的属性。当您尝试访问不在实例的属性时,JavaScript引擎将尝试在原型对象中查找。
进行演示,请查看以下代码:<span>class Foo {} </span><span>console.log(typeof Foo); // "function" </span>>
可以在运行时创建和修改这些原型对象。最初,我试图将课程用于动物和敌对:
<span>class Animal(object): </span> <span>def walk(self): </span> <span># ... </span> <span>class Hostile(object): </span> <span>def attack(self, target): </span> <span># ... </span> <span>class Dog(Animal): </span> <span># ... </span> <span>class Cat(Animal, Hostile): </span> <span># ... </span> dave <span>= Cat(); </span>dave<span>.walk(); </span>dave<span>.attack(target); </span>
上面的方法是不起作用的,因为类方法是>不枚举的。实际上,这意味着对象。分配(...)不从类复制方法。这也使得很难创建一个将方法从一个类复制到另一个类的函数。但是,我们可以手动复制每种方法:
><span>interface Hostile { </span> <span>attack(); </span><span>} </span> <span>class Animal { </span> <span>walk(); </span><span>} </span> <span>class Dog extends Animal { </span> <span>// ... </span><span>} </span> <span>class Cat extends Animal implements Hostile { </span> <span>attack() { </span> <span>// ... </span> <span>} </span><span>} </span>
>另一种方法是抛弃类并使用对象作为混合物。积极的副作用是Mixin对象不能用于创建实例,以防止滥用。
<span>class Animal { </span> <span>// ... </span><span>} </span> <span>trait Hostile { </span> <span>// ... </span><span>} </span> <span>class Dog extends Animal { </span> <span>// ... </span><span>} </span> <span>class Cat extends Animal { </span> <span>use Hostile; </span> <span>// ... </span><span>} </span> <span>class Robot { </span> <span>use Hostile; </span> <span>// ... </span><span>} </span>pros
需要额外的代码
>我们可以利用该功能从子类内部的多个类中构成对象。请注意,object.sign(...)仍然与Mixin类无法正常工作,因此我在这里也使用了对象:
<span>class Foo {} </span><span>console.log(typeof Foo); // "function" </span>因为这是指在上下文中的类(使用不可算的方法),所以object.shassign(...,this)不复制cat的方法。相反,您必须在此上明确设置此字段和方法,以便object.Assign()能够应用这些字段和方法,例如:
>
<span>class IAnimal { </span> <span>walk() { </span> <span>throw new Error('Not implemented'); </span> <span>} </span><span>} </span> <span>class Dog extends IAnimal { </span> <span>// ... </span><span>} </span> <span>const robbie = new Dog(); </span>robbie<span>.walk(); // Throws an error </span>这种方法是不切实际的。因为您要返回一个新对象而不是实例,所以它基本上等同于:
我认为我们可以同意后者更可读。
<span>function <span>MyFunction</span> () { </span> <span>this.myOwnProperty = 1; </span><span>} </span><span>MyFunction.prototype.myProtoProperty = 2; </span> <span>const myInstance = new MyFunction(); </span> <span>// logs "1" </span><span>console.log(myInstance.myOwnProperty); </span><span>// logs "2" </span><span>console.log(myInstance.myProtoProperty); </span> <span>// logs "true", because "myOwnProperty" is a property of "myInstance" </span><span>console.log(myInstance.hasOwnProperty('myOwnProperty')); </span><span>// logs "false", because "myProtoProperty" isn’t a property of "myInstance", but "myInstance.__proto__" </span><span>console.log(myInstance.hasOwnProperty('myProtoProperty')); </span>>
pros
<span>class Animal { </span> <span>walk() { </span> <span>// ... </span> <span>} </span><span>} </span> <span>class Dog { </span> <span>// ... </span><span>} </span> <span>Object.assign(Dog.prototype, Animal.prototype); </span>
>它有效,我猜
>cons
滥用ES2015类
>现在,我们可以将任何类传递给敌对功能,该函数将返回一个新的类,结合敌对的新类,以及我们传递给该功能的任何类:
我们可以通过几个类进行管道应用多个混合素:
<span>Object.assign(Cat.prototype, { </span> <span>attack: Hostile.prototype.attack, </span> <span>walk: Animal.prototype.walk, </span><span>}); </span>您还可以将对象用作基类:
pros
<span>const Animal = { </span> <span>walk() { </span> <span>// ... </span> <span>}, </span><span>}; </span> <span>const Hostile = { </span> <span>attack(target) { </span> <span>// ... </span> <span>}, </span><span>}; </span> <span>class Cat { </span> <span>// ... </span><span>} </span> <span>Object.assign(Cat.prototype, Animal, Hostile); </span>
>更容易理解,因为所有信息都在类声明标题中
<span>class Answer { </span> <span>constructor(question) { </span> <span>return { </span> <span>answer: 42, </span> <span>}; </span> <span>} </span><span>} </span> <span>// { answer: 42 } </span><span>new Answer("Life, the universe, and everything"); </span>
cons >当我决定研究此主题并撰写有关它的文章时,我希望JavaScript的原型模型有助于生成课程。由于类语法使方法无法恢复,因此对象操纵变得更加困难,几乎不切实际。 类语法可能会产生幻想,即JavaScript是一种基于类的OOP语言,但事实并非如此。使用大多数方法,您将必须修改对象的原型以模仿多重继承。使用类工厂功能的最后一种方法是使用Mixins组成类的可接受策略。
如果出于任何原因,您仍然喜欢经典的编程,则可能需要研究编译为JavaScript的语言。例如,打字稿是JavaScript的超集,它添加了(可选的)静态键入和您将从其他经典OOP语言中识别的模式。 您是否要在项目中使用上述两种方法?您找到了更好的方法吗?在评论中让我知道! javaScript ES2015对象继承经常询问问题
>在JavaScript中的经典和原型继承之间有什么区别?一个类定义一个对象的蓝图,对象是类的实例。继承是通过从超类创建子类来实现的。另一方面,JavaScript使用原型继承,其中对象直接从其他对象继承。这是更灵活的,因为可以在运行时扩展或动态更改对象。 > javaScript如何处理多个继承? > javaScript ES2015中的'构造函数是什么?在javascript ES2015中如何使用它?用于创建和初始化类中的对象的特殊方法。在继承的上下文中,子类构造函数必须使用“超级”关键字调用超级类构造函数,然后才能使用'this'关键字。 > 如何在JavaScript中添加属性? >
结论
>'超级'关键字在JavaScript ES2015中如何工作?在对象的父上调用功能。当在构造函数中使用时,“超级”关键字单独出现,必须在使用“此”关键字之前使用。 “超级”关键字也可用于在方法中的父对象上调用函数。
> JavaScript中的“原型”是什么?在JavaScript中如何使用它在继承中?此属性是对另一个对象的原型对象的引用。创建函数时,其原型对象也会通过函数的原型属性创建并链接。当使用构造函数函数创建对象时,它从其构造函数的原型中继承了属性和方法。
javaScript不直接支持多个继承。但是,可以使用混合蛋白间接实现它。混合蛋白是一种涉及将属性从一个对象复制到另一个对象的技术。这允许对象从多个来源继承属性和方法。
>>
>我如何在JavaScript ES2015中的子类中覆盖一个方法?您可以通过简单地定义子类中具有相同名称的方法来覆盖子类中的方法。新方法将在子类的实例上调用。 > JavaScript中的“新”关键字用于创建类或构造函数函数的实例。在继承的上下文中,“新”关键字用于创建一个子类的实例,该子类从超级类继承属性和方法。>
以上是JavaScript ES2015中对象继承的模式的详细内容。更多信息请关注PHP中文网其他相关文章!