首頁 web前端 js教程 JavaScript物件導向程式設計(繼承實作方式)

JavaScript物件導向程式設計(繼承實作方式)

Mar 01, 2017 pm 03:06 PM

許多OO 語言都支援兩種繼承方式:介面繼承和實作繼承。介面繼承只繼承方法簽名,而實作繼承則繼承實際的方法。如前所述,由於函數沒有簽名,在ECMAScript 中無法實現介面繼承。 ECMAScript 只支援實現繼承,實現繼承主要是依靠原型鏈來實現的。在此,主要闡述一下,原型鏈繼承,借用建構子、組合繼承、原型式繼承、寄生式繼承、寄生組合繼承等。

1.原型鏈

ECMAScript 中描述了原型鏈的概念,並將原型鏈作為實現繼承的主要方法。其基本思想是利用原型讓一個引用型別繼承另一個引用型別的屬性和方法。簡單回顧一下建構子、原型和實例的關係:每個建構函式都有一個原型對象,原型對像都包含一個指向建構函式的指針,而實例都包含一個指向原型對象的內部指針。那麼,假如我們讓原型物件等於另一個類型的實例,結果會怎麼樣呢?顯然,此時的原型物件將包含一個指向另一個原型的指針,相應地,另一個原型中也包含一個指向另一個建構函數的指針。假如另一個原型又是另一個類型的實例,那麼上述關係依然成立,如此層層遞進,就構成了實例與原型的鏈條。這就是所謂原型鏈的基本概念。

function Person(){
this.name=”defaultName”;
} 
Person.property.doAction=function(){
alert(“talk”);
}
 
function Student(){
this.age=5;
}
Student.property=new Person();
Student.property.doSome=function(){
alert(“ homework”);
}
登入後複製

原型鏈雖然很強大,可以用它來實現繼承,但它也存在一些問題。其中,最主要的問題來自包含引用類型值的原型。想必大家還記得,我們​​前面介紹過包含引用類型值的原型屬性會被所有實例共享;而這也正是為什麼要在建構函數中,而不是在原型物件中定義屬性的原因。透過原型來實現繼承時,原型實際上會變成另一個類型的實例。於是,原先的實例屬性也就順理成章地變成了現在的原型屬性了。原型鏈的第二個問題是:在建立子類型的實例時,不能傳遞參數給超類型的建構函式。實際上,應該說是沒有辦法在不影響所有物件實例的情況下,給超類型的建構函式傳遞參數。有鑑於此,再加上前面剛剛討論過的由於原型中包含引用類型值所帶來的問題,實踐中很少會單獨使用原型鏈。

2.借用建構子

在解決原型中包含引用型別值所帶來問題的過程中,開發者開始使用一種叫做借用建構函式(constructor stealing)的技術(有時候也叫做偽造物件或經典繼承)。這種技術的基本思想相當簡單,即在子類型構造函數的內部呼叫超類型構造函數。別忘了,函數只不過是在特定環境中執行程式碼的對象,因此透過使用apply()和call()方法也可以在(將來)新建立的對像上執行建構函式。

function Person(name){
this.name=name;
} 
Person.property.doAction=function(){
alert(“talk”);
}
Person.property.showName=function(){
alert(this.name);
}
function Student(){
Person.call(this,name);
this.age=5;
}
登入後複製

如果只是藉用建構函數,那麼也將無法避免建構函數模式存在的問題-方法都在建構函式中定義,因此函數複用就無從談起了。 而且,在超類型的原型中定義的方法,對子類型而言也是不可見的,結果所有型別都只能使用建構子模式。考慮到這些問題,借用構造函數的技術也是很少單獨使用的。

3.組合繼承
組合繼承(combination inheritance),有時候也叫做偽經典繼承,指的是將原型鍊和借用構造函數的技術組合到一塊,從而發揮二者之長的一種繼承模式。背後的想法是使用原型鏈實現對原型屬性和方法的繼承,而藉由借用建構函式來實現實例屬性的繼承。這樣,既透過在原型上定義方法實現了函數復用,又能夠保證每個實例都有它自己的屬性。

function Person(name){
this.name=name;
this.loves=[“sing”,”paly games”]
}
Person.property.showLoves=function (){
alert(this.lovers);
}
function Student(name,age){
Person.class(this,name);
This.age=age;
}
Student.property=new Person();
Student.property.constructor=Student;
Student.property.showName=function(){
alert(this.name);
}
登入後複製

組合繼承避免了原型鍊和借用建構函數的缺陷,融合了它們的優點,成為JavaScript 中最常用的繼承模式。而且,instanceof 和isPrototypeOf()也能夠用來識別基於組合繼承所建立的物件。

 

4.原型式繼承

function object(o){
function F(){}
F.prototype = o;
return new F();
}
登入後複製

在沒有必要興師動眾地創建建構函數,而只想讓一個物件與另一個物件保持類似的情況下,原型式繼承是完全可以勝任的。不過別忘了,包含引用類型值的屬性總是會共用對應的值,就像使用原型模式一樣。

5.寄生組合式繼承

所謂寄生組合式繼承,即藉由借用建構函式來繼承屬性,透過原型鏈的混成形式來繼承方法。其背

後的基本想法是:不必為了指定子類型的原型而呼叫超類型的建構函數,我們所需要的無非就是超型別

原型的一個副本而已。本質上,就是使用寄生式繼承來繼承超類型的原型,然後再將結果指定給子類型

的原型。寄生組合式繼承的基本模式如下圖所示。

function inheritPrototype(subType, superType){
var prototype = object(superType.prototype); //创建对象
prototype.constructor = subType; //增强对象
subType.prototype = prototype; //指定对象
}
登入後複製

个参数:子类型构造函数和超类型构造函数。在函数内部,第一步是创建超类型原型的一个副本。第二步是为创建的副本添加constructor 属性,从而弥补因重写原型而失去的默认的constructor 属性。最后一步,将新创建的对象(即副本)赋值给子类型的原型。这样,我们就可以用调用inheritPrototype()函数的语句,去替换前面例子中为子类型原型赋值的语句了。

集寄生式继承和组合继承的优点与一身,是实现基于类型继承的最有效方式。

 以上就是JavaScript面向对象编程(继承实现方式)的内容,更多相关内容请关注PHP中文网(www.php.cn)!


本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

C++ 函式繼承詳解:如何在繼承中使用「基底類別指標」和「衍生類別指標」? C++ 函式繼承詳解:如何在繼承中使用「基底類別指標」和「衍生類別指標」? May 01, 2024 pm 10:27 PM

在函數繼承中,使用「基底類別指標」和「衍生類別指標」來理解繼承機制:基底類別指標指向派生類別物件時,執行向上轉型,只存取基底類別成員。派生類別指標指向基底類別物件時,執行向下轉型(不安全),必須謹慎使用。

C++ 函式繼承詳解:如何偵錯繼承中出現的錯誤? C++ 函式繼承詳解:如何偵錯繼承中出現的錯誤? May 02, 2024 am 09:54 AM

繼承錯誤調試技巧:確保正確的繼承關係。使用偵錯器逐步執行程式碼,檢查變數值。確保正確使用virtual修飾符。檢查隱藏的繼承帶來的菱形繼承問題。檢查抽象類別中未實現的純虛函數。

C++ 函式繼承詳解:如何理解繼承中的「is-a」與「has-a」關係? C++ 函式繼承詳解:如何理解繼承中的「is-a」與「has-a」關係? May 02, 2024 am 08:18 AM

C++函式繼承詳解:掌握「is-a」和「has-a」關係什麼是函式繼承?函數繼承是C++中一種將衍生類別中定義的方法與基底類別中定義的方法關聯起來的技術。它允許衍生類別存取和重寫基底類別的方法,從而擴展了基底類別的功能。 「is-a」和「has-a」關係在函數繼承中,「is-a」關係指派生類別是基底類別的子類型,也就是說,衍生類別「繼承」了基底類別的特性和行為。 「has-a」關係指派生類別包含對基底類別物件的參考或指針,也就是說,衍生類別「擁有」了基底類別物件。語法以下是如何實作函數繼承的語法:classDerivedClass:pu

探索Go語言中的物件導向編程 探索Go語言中的物件導向編程 Apr 04, 2024 am 10:39 AM

Go語言支援物件導向編程,透過型別定義和方法關聯實作。它不支援傳統繼承,而是透過組合實現。介面提供了類型間的一致性,允許定義抽象方法。實戰案例展示如何使用OOP管理客戶訊息,包括建立、取得、更新和刪除客戶操作。

C++ 中繼承和多態性如何影響類別的耦合度? C++ 中繼承和多態性如何影響類別的耦合度? Jun 05, 2024 pm 02:33 PM

繼承和多態性會影響類別的耦合度:繼承會增加耦合度,因為衍生類別依賴基底類別。多態性可以降低耦合度,因為物件可以透過虛擬函數和基底類別指標以一致的方式回應訊息。最佳實踐包括謹慎使用繼承、定義公共介面、避免在基底類別中新增資料成員,以及透過依賴注入解耦類別。實戰案例顯示如何使用多態性和依賴注入來降低銀行帳戶應用程式中的耦合度。

PHP高階特性:物件導向程式設計的最佳實踐 PHP高階特性:物件導向程式設計的最佳實踐 Jun 05, 2024 pm 09:39 PM

PHP中OOP最佳實務包括命名約定、介面與抽象類別、繼承與多型、依賴注入。實戰案例包括:使用倉庫模式管理數據,使用策略模式實現排序。

Golang中有類似類別的物件導向特性嗎? Golang中有類似類別的物件導向特性嗎? Mar 19, 2024 pm 02:51 PM

在Golang(Go語言)中並沒有傳統意義上的類別的概念,但它提供了一種稱為結構體的資料類型,透過結構體可以實現類似類別的物件導向特性。在本文中,我們將介紹如何使用結構體實現物件導向的特性,並提供具體的程式碼範例。結構體的定義和使用首先,讓我們來看看結構體的定義和使用方式。在Golang中,結構體可以透過type關鍵字定義,然後在需要的地方使用。結構體中可以包含屬

Go語言的物件導向特性解析 Go語言的物件導向特性解析 Apr 04, 2024 am 11:18 AM

Go語言支援物件導向編程,透過struct定義對象,使用指標接收器定義方法,並透過介面實現多態。物件導向特性在Go語言中提供了程式碼重用、可維護性和封裝,但也存在缺乏傳統類別和繼承的概念以及方法簽章強制型別轉換的限制。

See all articles