首頁 > web前端 > js教程 > JavaScript ES2015中對象繼承的模式

JavaScript ES2015中對象繼承的模式

Lisa Kudrow
發布: 2025-02-16 11:38:39
原創
820 人瀏覽過

JavaScript ES2015中對象繼承的模式

鑰匙要點

  • >使用ES2015,JavaScript現在具有專門定義類的語法,以保持代碼清潔,最小化層次結構深度並避免重複代碼。
  • >多重繼承(由某些經典OOP語言支持的功能)允許創建從多個基類繼承的類。但是,它遇到了鑽石問題,其中兩個父類定義了相同的方法。
  • 混合蛋白,僅包含方法的微小類是躲避鑽石問題的另一種策略。 Mixins不用擴展這些類,而是在另一個類中包含。
  • >
  • >儘管班級語法給出了一種幻想,即JavaScript是一種基於類的OOP語言,但事實並非如此。大多數方法都需要修改對象的原型以模仿多重繼承。使用類工廠功能是使用Mixins組成類的可接受策略。
  • JavaScript的
  • > ES2015(以前稱為ES6)的已久的到來,配備了專門定義類的語法。在本文中,我將探討是否可以利用類語法來撰寫較小零件的類。
JavaScript ES2015中對象繼承的模式>將層次深度保持在最低限度對於保持代碼清潔很重要。對您如何拆分課程的方式很聰明。對於大型代碼庫,一種選擇是創建較小零件的類。撰寫課程。這也是避免重複代碼的常見策略。

想像我們正在建立一個玩家生活在動物世界中的遊戲。有些是朋友,有些是敵對的(像我這樣的狗人可能會說所有貓都是敵對的生物)。我們可以創建一個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>
登入後複製
登入後複製
多個繼承遭受鑽石問題(其中兩個父類定義相同的方法)。某些語言通過實施其他策略(例如)來避免此問題。 混合素是僅包含方法的小類。 Mixin並沒有擴展這些課程,而是將Mixins包含在另一個類中。例如,在PHP中,使用特徵實現Mixin。

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 {...}描述了一個名為foo

的類

類foo擴展bar {...}描述了一個foo的類,該類擴展了另一個類,bar

>

在類塊中,我們可以定義該類的屬性。在本文中,我們只需要了解構造函數和方法:
  • 構建器(){...}是一個保留函數,在創建時執行(new foo())>
  • > foo(){...}創建一個名為foo
  • 的方法

級語法主要是JavaScript原型模型上的句法糖。它不是創建類,而是創建一個函數構造函數:

>
  • 的要點是,JavaScript不是基於類的OOP語言。甚至可能認為語法是欺騙性的,給人的印像是。
  • 組成ES2015類
  • 可以通過創建一個拋出錯誤的虛擬方法來模仿
  • 接口。一旦繼承,就必須覆蓋該功能以避免錯誤:

如前所述,這種方法依賴於繼承。要繼承多個類,我們將需要多個繼承或混合素。

<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上獲得。

>

object.assign(childclass.protype,mixin ...)

> 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

    混合蛋白不能初始化
  • >
cons

需要額外的代碼
  • object.assign()有點晦澀
  • 與ES2015類合作的重塑原型繼承
  • 在構造函數中編寫對象
  • >
>使用ES2015類,您可以通過在構造函數中返回對象來覆蓋實例:

>我們可以利用該功能從子類內部的多個類中構成對象。請注意,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類語法
零收益

濫用ES2015類
  • 類工廠功能
  • 這種方法利用JavaScript在運行時定義類的能力。
  • 首先,我們需要基礎類。在我們的例子中,動物和機器人充當基礎類別。如果您想從頭開始,一個空的班級也可以。
  • >
接下來,我們必須創建一個返回新類的工廠功能,該函數擴展了類基礎,該類作為參數傳遞。這些是混合物:

>現在,我們可以將任何類傳遞給敵對功能,該函數將返回一個新的類,結合敵對的新類,以及我們傳遞給該功能的任何類:>

我們可以通過幾個類進行管道應用多個混合素:

<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語言中識別的模式。 >

您是否要在項目中使用上述兩種方法?您找到了更好的方法嗎?在評論中讓我知道!

>

>本文是由傑夫·莫特(Jeff Mott),斯科特·莫利納里(Scott Molinari),維爾丹·蘇菲奇(Vildan Softic)和瓊·元(Joan Yin )進行了審查。感謝SitePoint所有的同行評審器製作SitePoint內容的最佳功能!

javaScript ES2015對象繼承經常詢問問題 >在JavaScript中的經典和原型繼承之間有什麼區別?一個類定義一個對象的藍圖,對像是類的實例。繼承是通過從超類創建子類來實現的。另一方面,JavaScript使用原型繼承,其中對象直接從其他對象繼承。這是更靈活的,因為可以在運行時擴展或動態更改對象。

>

>'超級'關鍵字在JavaScript ES2015中如何工作?在對象的父上調用功能。當在構造函數中使用時,“超級”關鍵字單獨出現,必須在使用“此”關鍵字之前使用。 “超級”關鍵字也可用於在方法中的父對像上調用函數。 >

> JavaScript中的“原型”是什麼?在JavaScript中如何使用它在繼承中?此屬性是對另一個對象的原型對象的引用。創建函數時,其原型對像也會通過函數的原型屬性創建並鏈接。當使用構造函數函數創建對象時,它從其構造函數的原型中繼承了屬性和方法。

> javaScript如何處理多個繼承?

javaScript不直接支持多個繼承。但是,可以使用混合蛋白間接實現它。混合蛋白是一種涉及將屬性從一個對象複製到另一個對象的技術。這允許對像從多個來源繼承屬性和方法。

>

> javaScript ES2015中的'構造函數是什麼?在javascript ES2015中如何使用它?用於創建和初始化類中的對象的特殊方法。在繼承的上下文中,子類構造函數必須使用“超級”關鍵字調用超級類構造函數,然後才能使用'this'關鍵字。 >

JavaScript ES2015中的“擴展”關鍵字用於從超級類創建子類。子類繼承了超類的所有屬性和方法,但也可以添加新的屬性或覆蓋繼承的屬性。 >在JavaScript中,“類”是一種用作創建對象的藍圖的函數。它封裝了在該數據上運行的數據和功能。另一方面,“原型”是一個對象,其他對像從中繼承屬性和方法。

>

>我如何在JavaScript ES2015中的子類中覆蓋一個方法?您可以通過簡單地定義子類中具有相同名稱的方法來覆蓋子類中的方法。新方法將在子類的實例上調用。 > JavaScript中的“新”關鍵字用於創建類或構造函數函數的實例。在繼承的上下文中,“新”關鍵字用於創建一個子類的實例,該子類從超級類繼承屬性和方法。

如何在JavaScript中添加屬性? >

>在JavaScript中,您可以通過簡單地將值分配給原型對像上的屬性來將屬性添加到對象的原型中。然後,此屬性將由從構造函數函數創建的所有對象繼承。

>

以上是JavaScript ES2015中對象繼承的模式的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板