想像我們正在建立一個玩家生活在動物世界中的遊戲。有些是朋友,有些是敵對的(像我這樣的狗人可能會說所有貓都是敵對的生物)。我們可以創建一個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>
>探索應用多種繼承和混合素的各種方法的時間。以下所有檢查的策略均可在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>
需要額外的代碼
>我們可以利用該功能從子類內部的多個類中構成對象。請注意,object.sign(...)仍然與Mixin類無法正常工作,因此我在這裡也使用了對象:
<span>class Foo {} </span><span>console.log(typeof Foo); // "function" </span>
>
<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中文網其他相關文章!