一文弄懂JavaScript的繼承方式
JavaScript中的繼承方式
問(wèn):JavaScript中有幾種繼承方式呢
emmm...六種?五種?還是四種來(lái)著...
這次記清楚了 一共有五種繼承方式
- 盜用構(gòu)造函數(shù) (經(jīng)典繼承方式 )
- 組合繼承
- 原型鏈?zhǔn)嚼^承
- 寄生式繼承
- 寄生式組合繼承
問(wèn):每種繼承方式是怎么實(shí)現(xiàn)的呢
盜用構(gòu)造函數(shù)
基本思路很簡(jiǎn)單:在子類構(gòu)造函數(shù)中調(diào)用父類構(gòu)造函數(shù)。因?yàn)楫吘购瘮?shù)就是在特定上下文中執(zhí)行代碼的簡(jiǎn)單對(duì)象,所以可以使用apply() 和 call() 方法以新創(chuàng)建的對(duì)象為上下文執(zhí)行構(gòu)造函數(shù)。
盜用構(gòu)造函數(shù)的一個(gè)優(yōu)點(diǎn)就是可以在子類構(gòu)造函數(shù)中向父類構(gòu)造函數(shù)傳參
function SuperType(name) { this.name = name this.sayName = function () { console.log(this.name); } } function SubType(name, age) { // 繼承 SuperType 并傳參 SuperType.call(this, name); //實(shí)例屬性 this.age = age } let instance1 = new SubType('zxc', 2) let instance2 = new SuperType('gyx') // instance1.sayHi() // ?類也不能訪問(wèn)父類原型上定義的方法,因此所有類型只能使用構(gòu)造函數(shù)模式 console.log(instance1); // SubType { name: 'zxc', sayName: [Function (anonymous)], age: 2 }
組合繼承
組合繼承(有時(shí)候也叫偽經(jīng)典繼承)綜合了原型鏈和盜用構(gòu)造函數(shù),將兩者的優(yōu)點(diǎn)集中了起來(lái)?;?本的思路是使用原型鏈繼承原型上的屬性和方法,而通過(guò)盜用構(gòu)造函數(shù)繼承實(shí)例屬性。 這樣既可以把方 法定義在原型上以實(shí)現(xiàn)重用,又可以讓每個(gè)實(shí)例都有自己的屬性。
function SuperType(name) { this.name = name this.colors = ['red', 'blue', 'green'] } SuperType.prototype.sayName = function () { console.log(this.name); } function SubType(name, age) { //繼承實(shí)例屬性 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
原型鏈?zhǔn)嚼^承
原型式繼承適用于這種情況:你有一個(gè)對(duì)象,想在它的基礎(chǔ)上再創(chuàng)建一個(gè)新對(duì)象。你需要把這個(gè)對(duì)象先傳給 object() ,然后再對(duì)返回的對(duì)象進(jìn)行適當(dāng)修改。
Object.create() 方法將原型式繼承的概念規(guī)范化了 這個(gè)方法接收兩個(gè)參數(shù):作為新對(duì)象原型的對(duì)象,以及給新對(duì)象定義額外屬性的對(duì)象(第二個(gè)可選)
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() 的第二個(gè)參數(shù)與 Object.defineProperties() 的第二個(gè)參數(shù)一樣:每個(gè)新增屬性都通過(guò)各自的描述符來(lái)描述
let anotherPerson = Object.create(person, { name: { value: "Greg" } }); console.log(anotherPerson.name); // "Greg"
寄生式繼承
寄生式繼承背后的思路類似于寄生構(gòu)造函數(shù)和工廠模式:創(chuàng)建一個(gè)實(shí)現(xiàn)繼承的函數(shù),以某種方式增強(qiáng)對(duì)象,然后返回這個(gè)對(duì)象。
function createAnother(original) { //通過(guò)調(diào)用函數(shù)創(chuàng)建一個(gè)對(duì)象 let clone = Object(original) clone.sayHi = function () { // 以某種方式增強(qiáng)這個(gè)對(duì)象 console.log("hi"); }; clone.sayName = function () { // 以某種方式增強(qiáng)這個(gè)對(duì)象 console.log(this.name); }; return clone; // 返回這個(gè)對(duì)象 } let person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; let anotherPerson = createAnother(person); anotherPerson.sayHi(); // "hi" anotherPerson.sayName(); // "hi"
寄生時(shí)組合繼承
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); // 第二次調(diào)用 SuperType() this.age = age; } SubType.prototype = new SuperType(); // 第一次調(diào)用 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上會(huì)有兩個(gè)屬性: name 和 colors 。它們都是 SuperType 的實(shí)例屬性,但現(xiàn)在成為了 SubType 的原型屬性。在調(diào)用 SubType構(gòu)造函數(shù)時(shí),也會(huì)調(diào)用SuperType 構(gòu)造函數(shù),這一次會(huì)在新對(duì)象上創(chuàng)建實(shí)例屬性 name 和 colors 。這兩個(gè)實(shí)例屬性會(huì)遮蔽原型上同名的屬性。
如圖所示,有兩組 name 和 colors 屬性:一組在實(shí)例上,另一組在 SubType 的原型上。這是 調(diào)用兩次 SuperType 構(gòu)造函數(shù)的結(jié)果,好在有辦法解決這個(gè)問(wèn)題。
寄生式組合繼承通過(guò)盜用構(gòu)造函數(shù)繼承屬性,但使用混合式原型鏈繼承方法。基本思路是不通過(guò)調(diào) 用父類構(gòu)造函數(shù)給子類原型賦值,而是取得父類原型的一個(gè)副本。說(shuō)到底就是使用寄生式繼承來(lái)繼承父 類原型,然后將返回的新對(duì)象賦值給子類原型。寄生式組合繼承的基本模式如下所示:
function inheritPrototype(subType, superType) { let prototype = object(superType.prototype); // 創(chuàng)建對(duì)象 prototype.constructor = subType; // 增強(qiáng)對(duì)象 subType.prototype = prototype; // 賦值對(duì)象 }
這個(gè) inheritPrototype() 函數(shù)實(shí)現(xiàn)了寄生式組合繼承的核心邏輯。這個(gè)函數(shù)接收兩個(gè)參數(shù):子 類構(gòu)造函數(shù)和父類構(gòu)造函數(shù)。在這個(gè)函數(shù)內(nèi)部,第一步是創(chuàng)建父類原型的一個(gè)副本。然后,給返回的 prototype 對(duì)象設(shè)置 constructor 屬性,解決由于重寫原型導(dǎo)致默認(rèn) constructor 丟失的問(wèn)題。最 后將新創(chuàng)建的對(duì)象賦值給子類型的原型。如下例所示,調(diào)用 inheritPrototype() 就可以實(shí)現(xiàn)前面例 子中的子類型原型賦值:
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); };
這里只調(diào)用了一次 SuperType 構(gòu)造函數(shù),避免了 SubType.prototype 上不必要也用不到的屬性, 因此可以說(shuō)這個(gè)例子的效率更高。而且,原型鏈仍然保持不變,因此 instanceof 操作符和 isPrototypeOf() 方法正常有效。寄生式組合繼承可以算是引用類型繼承的最佳模式。
到此這篇關(guān)于一文弄懂JavaScript的繼承方式的文章就介紹到這了,更多相關(guān)js繼承方式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
javascript實(shí)現(xiàn)緩動(dòng)動(dòng)畫效果
這篇文章主要為大家詳細(xì)介紹了javascript實(shí)現(xiàn)緩動(dòng)動(dòng)畫效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09JS實(shí)現(xiàn)DOM刪除節(jié)點(diǎn)操作示例
這篇文章主要介紹了JS實(shí)現(xiàn)DOM刪除節(jié)點(diǎn)操作,結(jié)合實(shí)例形式分析了javascript使用removeChild()操作頁(yè)面dom節(jié)點(diǎn)刪除功能的相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2018-04-04OpenLayers3實(shí)現(xiàn)地圖鷹眼以及地圖比例尺的添加
這篇文章主要為大家詳細(xì)介紹了OpenLayers3實(shí)現(xiàn)地圖鷹眼以及地圖比例尺的添加,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-09-09jsonp格式前端發(fā)送和后臺(tái)接受寫法的代碼詳解
jsonp是ajax提交的一種格式不會(huì)受跨域限制,這篇文章主要介紹了jsonp格式前端發(fā)送和后臺(tái)接受寫法的代碼詳解,需要的朋友可以參考下2019-11-11整理的比較全的event對(duì)像在ie與firefox瀏覽器中的區(qū)別
event對(duì)像在IE與FF中的區(qū)別,本文整理了很多,個(gè)人感覺還是比較全面的,需要的朋友可以收藏下2013-11-11JS+CSS實(shí)現(xiàn)可以凹陷顯示選中單元格的方法
這篇文章主要介紹了JS+CSS實(shí)現(xiàn)可以凹陷顯示選中單元格的方法,實(shí)例分析了javascript操作css的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-03-03javascript實(shí)現(xiàn)的樣式表(CSS) 格式整理與壓縮
javascript實(shí)現(xiàn)的樣式表(CSS) 格式整理與壓縮,可以分為多行與單行,非常不錯(cuò)。2010-05-05原生JavaScript實(shí)現(xiàn)remove()和recover()功能示例
這篇文章主要介紹了原生JavaScript實(shí)現(xiàn)remove()和recover()功能,結(jié)合實(shí)例形式分析了javascript實(shí)現(xiàn)類似jQueryremove()和recover()功能的自定義函數(shù),需要的朋友可以參考下2018-07-07