搜尋
首頁web前端js教程JavaScript中關於繼承的六種實作方式

JavaScript中關於繼承的六種實作方式

Oct 23, 2017 am 09:44 AM
javascriptjs方式

javascript 中關於繼承的描述:

            許多物件導向語言支援兩種繼承的方式:介面繼承與實作繼承。介面繼承只繼承方法簽名,而實作繼承則繼承實際的方法。在 javascript 中由於函數沒有簽章也就無法實作介面繼承,而只支援實作繼承,而且實作繼承主要透過原型鏈來實現的。

            先引用下官方文件對原型鏈的描述:其基本想法是利用原型讓一個引用型別繼承另一個引用型別的屬性與方法。要理解這個概念要先弄清楚建構函數,原型,和實例的關係:每個建構函數(只要是函數)都有一個prototype 屬性該屬性指向一個物件(這個物件就是建構函數的原型物件);原型物件(只要是物件)中都有一個constructor 屬性該屬性指向一個建構子;而實例中都包含一個指向原型物件的內部指標[[Prototype]]。說白了就是原型鏈的建構是透過將一個類型的實例賦值給另一個建構函數的原型來實現的。這樣子類型就可以存取定義在超類型上的所有屬性和方法了。每個對像都有自己的原型對象,以原型對象為模板從原型對象繼承屬性和方法,原型對像也可以有自己的原型並從中繼承屬性和方法,一層一層,以此類推,這種關係被稱為原型鏈它解釋了為何一個物件會擁有定義在其他物件上的屬性和方法。


javascript 中實作繼承的六種方式:

            1、原型鏈

            2、使用建構子
## )


            4、原型式繼承


        

#       
            6、寄生組合式繼承(使用組合繼承與寄生式繼承)

1、原型鏈

#

// 实现原型链的一种基本模式
function SuperType(){
            this.property = true;
}
SuperType.prototype.getSuperValue = function(){
            return this.property;
};
function SubType(){
            this.subproperty = false;
}

// 继承,用 SuperType 类型的一个实例来重写 SubType 类型的原型对象
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function(){
            return this.subproperty;
};
var instance = new SubType();
alert(instance.getSuperValue());     // true

PS:SubType 繼承了 SuperType,而繼承是透過創建 SuperType 的實例,並將該實例賦值給 SubType 的原型實現的。實現的本質是重寫子類型的原型對象,並以一個新類型的實例取代。子類型的新原型物件中有一個內部屬性 [[Prototype]] 指向了 SuperType 的原型,還有一個從 SuperType 原型繼承過來的屬性 constructor 指向了 SuperType 建構子。最終的原型鍊是這樣的:instance 指向SubType 的原型,SubType 的原型又指向SuperType 的原型,SuperType 的原型又指向Object 的原型(所有函數的預設原型都是Object 的實例,因此預設原型都會包含一個內部指針,指向Object.prototype)。
原型鏈的缺點:
           1、透過原型來實現繼承時,原型實際上會變成另一個類型的實例。於是,原先的實例屬性也就順理成章地變成了現在的原型屬性,並且會被所有的實例共享。這樣理解:在超型別建構函式中定義的參考型別值的實例屬性,會在子型別原型上變成原型屬性被所有子型別實例所共用。
           2、建立子類型的實例時,無法傳遞參數給超類型的建構子。

2、借用建構子(也稱為偽造物件或經典繼承)

// 在子类型构造函数的内部调用超类型构造函数;使用 apply() 或 call() 方法将父对象的构造函数绑定在子对象上
function SuperType(){
            // 定义引用类型值属性
            this.colors = ["red","green","blue"];
}
function SubType(){
            // 继承 SuperType,在这里还可以给超类型构造函数传参
            SuperType.call(this);
}
var instance1 = new SubType();
instance1.colors.push("purple");
alert(instance1.colors);     // "red,green,blue,purple"

var instance2 = new SubType();
alert(instance2.colors);     // "red,green,blue"

PS:透過使用apply() 或call() 方法,我們實際上是在將要創建的SubType 實例的環境下呼叫了SuperType 建構子。這樣一來,就會在新 SubType 物件上執行 SuperType() 函數中定義的所有物件初始化程式碼。結果 SubType 的每個實例都會有自己的 colors 屬性的副本了。
借用建構函式的優點是解決了原型鏈實作繼承存在的兩個問題;借用建構函式的缺點是方法都在建構函式中定義,因此函式復用就無法實作了。而且,在超類型的原型中定義的方法,對子類型而言也是不可見的,結果所有型別都只能使用建構函式模式。

3、組合繼承(也稱偽經典繼承)

// 将原型链和借用构造函数的技术组合到一块。使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。
这样,既通过在原型上定义方法实现了函数复用,又能够保证每个实例都有自己的属性。
function SuperType(name){
            this.name = name;
            this.colors = ["red","green","blue"];
}
SuperType.prototype.sayName = function(){
            alert(this.name);
};
function SubType(name,age){
            // 借用构造函数方式继承属性
            SuperType.call(this,name);
            this.age = age;
}
// 原型链方式继承方法
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
            alert(this.age);
};
var instance1 = new SubType("luochen",22);
instance1.colors.push("purple");
alert(instance1.colors);      // "red,green,blue,purple"
instance1.sayName();
instance1.sayAge();

var instance2 = new SubType("tom",34);
alert(instance2.colors);      // "red,green,blue"
instance2.sayName();
instance2.sayAge();

PS:組合繼承避免了原型鍊和借用建構函式的缺陷,融合了它們的優點,成為javascript 中最常用的繼承模式。而且,使用 instanceof 運算子和 isPrototype() 方法也能夠用於識別基於組合繼承所建立的物件。但是,它也有自己的不足。最大的問題是無論在什麼情況下,都會呼叫兩次超類型建構函數:一次是在建立子類型原型的時候,另一次是在子類型建構函式內部。

4、原型式繼承

// 借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型。
1、自定义一个函数来实现原型式继承
function object(o){
            function F(){}
            F.prototype = o;
            return new F();
}

PS:在object() 函數內部,先建立一個臨時性的建構函數,然後將傳入的物件當作這個建構函數的原型,最後傳回這個臨時型別的一個新實例。實質上,object() 對傳入其中的物件執行了一次淺複製。
2、使用 Object.create() 方法實作原型式繼承。這個方法接收兩個參數:一是用作新物件原型的物件和一個為新物件定義額外屬性的物件。在傳入一個參數的情況下,此方法與 object() 方法作用一致。
在傳入第二個參數的情況下,指定的任何屬性都會覆寫原型物件上的同名屬性。

var person = {
            name: "luochen",
            colors: ["red","green","blue"]
}; 
var anotherPerson1 = Object.create(person,{
            name: {
                    value: "tom"
            }
});
var anotherPerson2 = Object.create(person,{
            name: {
                    value: "jerry"
            }
});
anotherPerson1.colors.push("purple");
alert(anotherPerson1.name);     // "tom"
alert(anotherPerson2.name);     // "jerry"
alert(anotherPerson1.colors);    // "red,green,blue,purple"
alert(anotherPerson2.colors);    // "red,green,bule,purple";

PS:只是想讓一個物件與另一個物件類似的情況下,原型式繼承是完全可以勝任的。但是缺點是:包含引用類型值的屬性總是會共用對應的值。

5、寄生式繼承

// 创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后返回这个对象
function createPerson(original){
            var clone = Object.create(original);   // 通过 Object.create() 函数创建一个新对象
            clone.sayGood = function(){              // 增强这个对象
                        alert("hello world!!!");
            };
            return clone;                                      // 返回这个对象 
}

PS:在主要考慮物件而不是自訂類型和建構函數的情況下,寄生式繼承也是一個有用的模式。此模式的缺點是做不到函數重複使用。

6、寄生組合式繼承

// 通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型
function SuperType(name){
            this.name = name;
            this.colors = ["red","green","blue"];
}
SuperType.prototype.sayName = function(){
            alert(this.name);
};
function SubType(name,age){
            SuperType.call(this,name);
            this.age = age;
}
// 创建超类型原型的一个副本
var anotherPrototype = Object.create(SuperType.prototype);
// 重设因重写原型而失去的默认的 constructor 属性
anotherPrototype.constructor = SubType;
// 将新创建的对象赋值给子类型的原型
SubType.prototype = anotherPrototype;

SubType.prototype.sayAge = function(){
            alert(this.age);
};
var instance1 = new SubType("luochen",22);
instance1.colors.push("purple");
alert(instance1.colors);      // "red,green,blue,purple"
instance1.sayName();
instance1.sayAge();

var instance2 = new SubType("tom",34);
alert(instance2.colors);      // "red,green,blue"
instance2.sayName();
instance2.sayAge();

PS:這個範例的高效率體現在它只呼叫一次SuperType 建構函數,並且因此避免了在SubType.prototype 上面建立不必要,多餘的屬性。同時,原型鏈還能維持不變;因此也能夠正常使用 instance 運算元和 isPrototype() 方法。

以上是JavaScript中關於繼承的六種實作方式的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
JavaScript的演變:當前的趨勢和未來前景JavaScript的演變:當前的趨勢和未來前景Apr 10, 2025 am 09:33 AM

JavaScript的最新趨勢包括TypeScript的崛起、現代框架和庫的流行以及WebAssembly的應用。未來前景涵蓋更強大的類型系統、服務器端JavaScript的發展、人工智能和機器學習的擴展以及物聯網和邊緣計算的潛力。

神秘的JavaScript:它的作用以及為什麼重要神秘的JavaScript:它的作用以及為什麼重要Apr 09, 2025 am 12:07 AM

JavaScript是現代Web開發的基石,它的主要功能包括事件驅動編程、動態內容生成和異步編程。 1)事件驅動編程允許網頁根據用戶操作動態變化。 2)動態內容生成使得頁面內容可以根據條件調整。 3)異步編程確保用戶界面不被阻塞。 JavaScript廣泛應用於網頁交互、單頁面應用和服務器端開發,極大地提升了用戶體驗和跨平台開發的靈活性。

Python還是JavaScript更好?Python還是JavaScript更好?Apr 06, 2025 am 12:14 AM

Python更适合数据科学和机器学习,JavaScript更适合前端和全栈开发。1.Python以简洁语法和丰富库生态著称,适用于数据分析和Web开发。2.JavaScript是前端开发核心,Node.js支持服务器端编程,适用于全栈开发。

如何安裝JavaScript?如何安裝JavaScript?Apr 05, 2025 am 12:16 AM

JavaScript不需要安裝,因為它已內置於現代瀏覽器中。你只需文本編輯器和瀏覽器即可開始使用。 1)在瀏覽器環境中,通過標籤嵌入HTML文件中運行。 2)在Node.js環境中,下載並安裝Node.js後,通過命令行運行JavaScript文件。

在Quartz中如何在任務開始前發送通知?在Quartz中如何在任務開始前發送通知?Apr 04, 2025 pm 09:24 PM

如何在Quartz中提前發送任務通知在使用Quartz定時器進行任務調度時,任務的執行時間是由cron表達式設定的。現�...

在JavaScript中,如何在構造函數中獲取原型鏈上函數的參數?在JavaScript中,如何在構造函數中獲取原型鏈上函數的參數?Apr 04, 2025 pm 09:21 PM

在JavaScript中如何獲取原型鏈上函數的參數在JavaScript編程中,理解和操作原型鏈上的函數參數是常見且重要的任�...

微信小程序webview中Vue.js動態style位移失效是什麼原因?微信小程序webview中Vue.js動態style位移失效是什麼原因?Apr 04, 2025 pm 09:18 PM

在微信小程序web-view中使用Vue.js動態style位移失效的原因分析在使用Vue.js...

在Tampermonkey中如何實現對多個鏈接的並發GET請求並依次判斷返回結果?在Tampermonkey中如何實現對多個鏈接的並發GET請求並依次判斷返回結果?Apr 04, 2025 pm 09:15 PM

在Tampermonkey中如何對多個鏈接進行並發GET請求並依次判斷返回結果?在Tampermonkey腳本中,我們經常需要對多個鏈...

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
3 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。