一文弄懂JavaScript的繼承方式
JavaScript中的繼承方式
問:JavaScript中有幾種繼承方式呢
emmm...六種?五種?還是四種來著...
這次記清楚了 一共有五種繼承方式
- 盜用構造函數 (經典繼承方式 )
- 組合繼承
- 原型鏈式繼承
- 寄生式繼承
- 寄生式組合繼承
問:每種繼承方式是怎么實現的呢
盜用構造函數
基本思路很簡單:在子類構造函數中調用父類構造函數。因為畢竟函數就是在特定上下文中執(zhí)行代碼的簡單對象,所以可以使用apply() 和 call() 方法以新創(chuàng)建的對象為上下文執(zhí)行構造函數。
盜用構造函數的一個優(yōu)點就是可以在子類構造函數中向父類構造函數傳參
function SuperType(name) { this.name = name this.sayName = function () { console.log(this.name); } } function SubType(name, age) { // 繼承 SuperType 并傳參 SuperType.call(this, name); //實例屬性 this.age = age } let instance1 = new SubType('zxc', 2) let instance2 = new SuperType('gyx') // instance1.sayHi() // ?類也不能訪問父類原型上定義的方法,因此所有類型只能使用構造函數模式 console.log(instance1); // SubType { name: 'zxc', sayName: [Function (anonymous)], age: 2 }
組合繼承
組合繼承(有時候也叫偽經典繼承)綜合了原型鏈和盜用構造函數,將兩者的優(yōu)點集中了起來?;?本的思路是使用原型鏈繼承原型上的屬性和方法,而通過盜用構造函數繼承實例屬性。 這樣既可以把方 法定義在原型上以實現重用,又可以讓每個實例都有自己的屬性。
function SuperType(name) { this.name = name this.colors = ['red', 'blue', 'green'] } SuperType.prototype.sayName = function () { console.log(this.name); } function SubType(name, age) { //繼承實例屬性 SuperType.call(this, name) this.age = age } //繼承原型方法 SubType.prototype = new SuperType() SubType.prototype.sayAge = function () { console.log(this.age); } let instance1 = new SubType('zxc', '22') instance1.sayName() //zxc instance1.sayAge() // 22 let instance2 = new SubType("Greg", 27); console.log(instance2.colors); // "red,blue,green" instance2.sayName(); // "Greg"; instance2.sayAge(); // 27
原型鏈式繼承
原型式繼承適用于這種情況:你有一個對象,想在它的基礎上再創(chuàng)建一個新對象。你需要把這個對象先傳給 object() ,然后再對返回的對象進行適當修改。
Object.create() 方法將原型式繼承的概念規(guī)范化了 這個方法接收兩個參數:作為新對象原型的對象,以及給新對象定義額外屬性的對象(第二個可選)
let person = { name: "Nicholas", age: 12, friends: ["Shelby", "Court", "Van"] }; let anotherPerson1 = Object.create(person); anotherPerson1.name = 'lll' anotherPerson1.friends.push('zxc') console.log(anotherPerson1); // { name: 'lll' } console.log(person.friends); //[ 'Shelby', 'Court', 'Van', 'zxc' ]
// ? Object.create() 的第二個參數與 Object.defineProperties() 的第二個參數一樣:每個新增屬性都通過各自的描述符來描述
let anotherPerson = Object.create(person, { name: { value: "Greg" } }); console.log(anotherPerson.name); // "Greg"
寄生式繼承
寄生式繼承背后的思路類似于寄生構造函數和工廠模式:創(chuàng)建一個實現繼承的函數,以某種方式增強對象,然后返回這個對象。
function createAnother(original) { //通過調用函數創(chuàng)建一個對象 let clone = Object(original) clone.sayHi = function () { // 以某種方式增強這個對象 console.log("hi"); }; clone.sayName = function () { // 以某種方式增強這個對象 console.log(this.name); }; return clone; // 返回這個對象 } let person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; let anotherPerson = createAnother(person); anotherPerson.sayHi(); // "hi" anotherPerson.sayName(); // "hi"
寄生時組合繼承
function SuperType(name) { this.name = name this.colors = ['red', 'blue'] } SuperType.prototype.sayName = function () { console.log(this.name) } function SubType(name, age) { SuperType.call(this, name); // 第二次調用 SuperType() this.age = age; } SubType.prototype = new SuperType(); // 第一次調用 SuperType() SubType.prototype.constructor = SubType; SubType.prototype.sayAge = function () { console.log(this.age); }; let instance1 = new SubType('zxc', 12) console.log(instance1);
在上面的代碼執(zhí)行后, SubType.prototype上會有兩個屬性: name 和 colors 。它們都是 SuperType 的實例屬性,但現在成為了 SubType 的原型屬性。在調用 SubType構造函數時,也會調用SuperType 構造函數,這一次會在新對象上創(chuàng)建實例屬性 name 和 colors 。這兩個實例屬性會遮蔽原型上同名的屬性。
如圖所示,有兩組 name 和 colors 屬性:一組在實例上,另一組在 SubType 的原型上。這是 調用兩次 SuperType 構造函數的結果,好在有辦法解決這個問題。
寄生式組合繼承通過盜用構造函數繼承屬性,但使用混合式原型鏈繼承方法?;舅悸肥?strong>不通過調 用父類構造函數給子類原型賦值,而是取得父類原型的一個副本。說到底就是使用寄生式繼承來繼承父 類原型,然后將返回的新對象賦值給子類原型。寄生式組合繼承的基本模式如下所示:
function inheritPrototype(subType, superType) { let prototype = object(superType.prototype); // 創(chuàng)建對象 prototype.constructor = subType; // 增強對象 subType.prototype = prototype; // 賦值對象 }
這個 inheritPrototype() 函數實現了寄生式組合繼承的核心邏輯。這個函數接收兩個參數:子 類構造函數和父類構造函數。在這個函數內部,第一步是創(chuàng)建父類原型的一個副本。然后,給返回的 prototype 對象設置 constructor 屬性,解決由于重寫原型導致默認 constructor 丟失的問題。最 后將新創(chuàng)建的對象賦值給子類型的原型。如下例所示,調用 inheritPrototype() 就可以實現前面例 子中的子類型原型賦值:
function SuperType(name) { this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function () { console.log(this.name); } function SubType(name, age) { SuperType.call(this, name) this.age = age; } inheritPrototype(SubType, SuperType); SubType.prototype.sayAge = function () { console.log(this.age); };
這里只調用了一次 SuperType 構造函數,避免了 SubType.prototype 上不必要也用不到的屬性, 因此可以說這個例子的效率更高。而且,原型鏈仍然保持不變,因此 instanceof 操作符和 isPrototypeOf() 方法正常有效。寄生式組合繼承可以算是引用類型繼承的最佳模式。
到此這篇關于一文弄懂JavaScript的繼承方式的文章就介紹到這了,更多相關js繼承方式內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
整理的比較全的event對像在ie與firefox瀏覽器中的區(qū)別
event對像在IE與FF中的區(qū)別,本文整理了很多,個人感覺還是比較全面的,需要的朋友可以收藏下2013-11-11原生JavaScript實現remove()和recover()功能示例
這篇文章主要介紹了原生JavaScript實現remove()和recover()功能,結合實例形式分析了javascript實現類似jQueryremove()和recover()功能的自定義函數,需要的朋友可以參考下2018-07-07