最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript的六種繼承方式(推薦)

 更新時間:2017年06月26日 10:57:58   作者:Xuthus  
繼承是面向?qū)ο缶幊讨杏忠环浅V匾母拍睿琂avaScript支持實(shí)現(xiàn)繼承,不支持接口繼承,實(shí)現(xiàn)繼承主要依靠原型鏈來實(shí)現(xiàn)的

繼承是面向?qū)ο缶幊讨杏忠环浅V匾母拍?,JavaScript支持實(shí)現(xiàn)繼承,不支持接口繼承,實(shí)現(xiàn)繼承主要依靠原型鏈來實(shí)現(xiàn)的。

原型鏈

首先得要明白什么是原型鏈,在一篇文章看懂proto和prototype的關(guān)系及區(qū)別中講得非常詳細(xì)

原型鏈繼承基本思想就是讓一個原型對象指向另一個類型的實(shí)例

function SuperType() { 
 this.property = true 
} 
SuperType.prototype.getSuperValue = function () { 
 return this.property 
} 
function SubType() { 
 this.subproperty = false 
} 
SubType.prototype = new SuperType() 
SubType.prototype.getSubValue = function () { 
 return this.subproperty 
} 
var instance = new SubType() 
console.log(instance.getSuperValue()) // true 

代碼定義了兩個類型SuperType和SubType,每個類型分別有一個屬性和一個方法,SubType繼承了SuperType,而繼承是通過創(chuàng)建SuperType的實(shí)例,并將該實(shí)例賦給SubType.prototype實(shí)現(xiàn)的。

實(shí)現(xiàn)的本質(zhì)是重寫原型對象,代之以一個新類型的實(shí)例,那么存在SuperType的實(shí)例中的所有屬性和方法,現(xiàn)在也存在于SubType.prototype中了。

我們知道,在創(chuàng)建一個實(shí)例的時候,實(shí)例對象中會有一個內(nèi)部指針指向創(chuàng)建它的原型,進(jìn)行關(guān)聯(lián)起來,在這里代碼SubType.prototype = new SuperType(),也會在SubType.prototype創(chuàng)建一個內(nèi)部指針,將SubType.prototype與SuperType關(guān)聯(lián)起來。

所以instance指向SubType的原型,SubType的原型又指向SuperType的原型,繼而在instance在調(diào)用getSuperValue()方法的時候,會順著這條鏈一直往上找。

添加方法

在給SubType原型添加方法的時候,如果,父類上也有同樣的名字,SubType將會覆蓋這個方法,達(dá)到重新的目的。 但是這個方法依然存在于父類中。

記住不能以字面量的形式添加,因?yàn)?,上面說過通過實(shí)例繼承本質(zhì)上就是重寫,再使用字面量形式,又是一次重寫了,但這次重寫沒有跟父類有任何關(guān)聯(lián),所以就會導(dǎo)致原型鏈截斷。

function SuperType() { 
 this.property = true 
} 
SuperType.prototype.getSuperValue = function () { 
 return this.property 
} 
function SubType() { 
 this.subproperty = false 
} 
SubType.prototype = new SuperType() 
SubType.prototype = { 
 getSubValue:function () { 
 return this.subproperty 
 } 
} 
var instance = new SubType() 
console.log(instance.getSuperValue()) // error 

問題

單純的使用原型鏈繼承,主要問題來自包含引用類型值的原型。

function SuperType() { 
 this.colors = ['red', 'blue', 'green'] 
} 
function SubType() { 
} 
SubType.prototype = new SuperType() 
var instance1 = new SubType() 
var instance2 = new SubType() 
instance1.colors.push('black') 
console.log(instance1.colors) // ["red", "blue", "green", "black"] 
console.log(instance2.colors) // ["red", "blue", "green", "black"] 

在SuperType構(gòu)造函數(shù)定義了一個colors屬性,當(dāng)SubType通過原型鏈繼承后,這個屬性就會出現(xiàn)SubType.prototype中,就跟專門創(chuàng)建了SubType.prototype.colors一樣,所以會導(dǎo)致SubType的所有實(shí)例都會共享這個屬性,所以instance1修改colors這個引用類型值,也會反映到instance2中。

借用構(gòu)造函數(shù)

此方法為了解決原型中包含引用類型值所帶來的問題。

這種方法的思想就是在子類構(gòu)造函數(shù)的內(nèi)部調(diào)用父類構(gòu)造函數(shù),可以借助apply()和call()方法來改變對象的執(zhí)行上下文

function SuperType() { 
 this.colors = ['red', 'blue', 'green'] 
} 
function SubType() { 
 // 繼承SuperType 
 SuperType.call(this) 
} 
var instance1 = new SubType() 
var instance2 = new SubType() 
instance1.colors.push('black') 
console.log(instance1.colors) // ["red", "blue", "green", "black"] 
console.log(instance2.colors) // ["red", "blue", "green"] 

在新建SubType實(shí)例是調(diào)用了SuperType構(gòu)造函數(shù),這樣以來,就會在新SubType對象上執(zhí)行SuperType函數(shù)中定義的所有對象初始化代碼。

結(jié)果,SubType的每個實(shí)例就會具有自己的colors屬性的副本了。

傳遞參數(shù)

借助構(gòu)造函數(shù)還有一個優(yōu)勢就是可以傳遞參數(shù)

function SuperType(name) { 
 this.name = name 
} 
function SubType() { 
 // 繼承SuperType 
 SuperType.call(this, 'Jiang') 
 this.job = 'student' 
} 
var instance = new SubType() 
console.log(instance.name) // Jiang 
console.log(instance.job) // student 

問題

如果僅僅借助構(gòu)造函數(shù),方法都在構(gòu)造函數(shù)中定義,因此函數(shù)無法達(dá)到復(fù)用

組合繼承(原型鏈+構(gòu)造函數(shù))

組合繼承是將原型鏈繼承和構(gòu)造函數(shù)結(jié)合起來,從而發(fā)揮二者之長的一種模式。

思路就是使用原型鏈實(shí)現(xiàn)對原型屬性和方法的繼承,而通過借用構(gòu)造函數(shù)來實(shí)現(xiàn)對實(shí)例屬性的繼承。

這樣,既通過在原型上定義方法實(shí)現(xiàn)了函數(shù)復(fù)用,又能夠保證每個實(shí)例都有它自己的屬性。

function SuperType(name) { 
 this.name = name 
 this.colors = ['red', 'blue', 'green'] 
} 
SuperType.prototype.sayName = function () { 
 console.log(this.name) 
} 
function SubType(name, job) { 
 // 繼承屬性 
 SuperType.call(this, name) 
 this.job = job 
} 
// 繼承方法 
SubType.prototype = new SuperType() 
SubType.prototype.constructor = SuperType 
SubType.prototype.sayJob = function() { 
 console.log(this.job) 
} 
var instance1 = new SubType('Jiang', 'student') 
instance1.colors.push('black') 
console.log(instance1.colors) //["red", "blue", "green", "black"] 
instance1.sayName() // 'Jiang' 
instance1.sayJob() // 'student' 
var instance2 = new SubType('J', 'doctor') 
console.log(instance2.colors) // //["red", "blue", "green"] 
instance2.sayName() // 'J' 
instance2.sayJob() // 'doctor' 

這種模式避免了原型鏈和構(gòu)造函數(shù)繼承的缺陷,融合了他們的優(yōu)點(diǎn),是最常用的一種繼承模式。

原型式繼承

借助原型可以基于已有的對象創(chuàng)建新對象,同時還不必因此創(chuàng)建自定義類型。

function object(o) { 
 function F() {} 
 F.prototype = o 
 return new F() 
} 

在object函數(shù)內(nèi)部,先創(chuàng)建一個臨時性的構(gòu)造函數(shù),然后將傳入的對象作為這個構(gòu)造函數(shù)的原型,最后返回這個臨時類型的一個新實(shí)例。

本質(zhì)上來說,object對傳入其中的對象執(zhí)行了一次淺復(fù)制。

var person = { 
 name: 'Jiang', 
 friends: ['Shelby', 'Court'] 
} 
var anotherPerson = object(person) 
console.log(anotherPerson.friends) // ['Shelby', 'Court'] 

這種模式要去你必須有一個對象作為另一個對象的基礎(chǔ)。

在這個例子中,person作為另一個對象的基礎(chǔ),把person傳入object中,該函數(shù)就會返回一個新的對象。

這個新對象將person作為原型,所以它的原型中就包含一個基本類型和一個引用類型。

所以意味著如果還有另外一個對象關(guān)聯(lián)了person,anotherPerson修改數(shù)組friends的時候,也會體現(xiàn)在這個對象中。

Object.create()方法

ES5通過Object.create()方法規(guī)范了原型式繼承,可以接受兩個參數(shù),一個是用作新對象原型的對象和一個可選的為新對象定義額外屬性的對象,行為相同,基本用法和上面的object一樣,除了object不能接受第二個參數(shù)以外。

var person = { 
 name: 'Jiang', 
 friends: ['Shelby', 'Court'] 
} 
var anotherPerson = Object.create(person) 
console.log(anotherPerson.friends) // ['Shelby', 'Court'] 

寄生式繼承

寄生式繼承的思路與寄生構(gòu)造函數(shù)和工廠模式類似,即創(chuàng)建一個僅用于封裝繼承過程的函數(shù)。

function createAnother(o) { 
 var clone = Object.create(o) // 創(chuàng)建一個新對象 
 clone.sayHi = function() { // 添加方法 
 console.log('hi') 
 } 
 return clone // 返回這個對象 
} 
var person = { 
 name: 'Jiang' 
} 
var anotherPeson = createAnother(person) 
anotherPeson.sayHi() 

基于person返回了一個新對象anotherPeson,新對象不僅擁有了person的屬性和方法,還有自己的sayHi方法。

在主要考慮對象而不是自定義類型和構(gòu)造函數(shù)的情況下,這是一個有用的模式。

寄生組合式繼承

在前面說的組合模式(原型鏈+構(gòu)造函數(shù))中,繼承的時候需要調(diào)用兩次父類構(gòu)造函數(shù)。

父類

function SuperType(name) { 
 this.name = name 
 this.colors = ['red', 'blue', 'green'] 
} 

第一次在子類構(gòu)造函數(shù)中

function SubType(name, job) { 
 // 繼承屬性 
 SuperType.call(this, name) 
 this.job = job 
} 

第二次將子類的原型指向父類的實(shí)例

// 繼承方法 
SubType.prototype = new SuperType() 

當(dāng)使用var instance = new SubType()的時候,會產(chǎn)生兩組name和color屬性,一組在SubType實(shí)例上,一組在SubType原型上,只不過實(shí)例上的屏蔽了原型上的。

使用寄生式組合模式,可以規(guī)避這個問題。

這種模式通過借用構(gòu)造函數(shù)來繼承屬性,通過原型鏈的混成形式來繼承方法。

基本思路:不必為了指定子類型的原型而調(diào)用父類的構(gòu)造函數(shù),我們需要的無非就是父類原型的一個副本。

本質(zhì)上就是使用寄生式繼承來繼承父類的原型,在將結(jié)果指定給子類型的原型。

function inheritPrototype(subType, superType) { 
 var prototype = Object.create(superType.prototype) 
 prototype.constructor = subType 
 subType.prototype = prototype 
} 

該函數(shù)實(shí)現(xiàn)了寄生組合繼承的最簡單形式。

這個函數(shù)接受兩個參數(shù),一個子類,一個父類。

第一步創(chuàng)建父類原型的副本,第二步將創(chuàng)建的副本添加constructor屬性,第三部將子類的原型指向這個副本。

function SuperType(name) { 
 this.name = name 
 this.colors = ['red', 'blue', 'green'] 
} 
SuperType.prototype.sayName = function () { 
 console.log(this.name) 
} 
function SubType(name, job) { 
 // 繼承屬性 
 SuperType.call(this, name) 
 this.job = job 
} 
// 繼承 
inheritPrototype(SubType, SuperType) 
var instance = new SubType('Jiang', 'student') 
instance.sayName() 

補(bǔ)充:直接使用Object.create來實(shí)現(xiàn),其實(shí)就是將上面封裝的函數(shù)拆開,這樣演示可以更容易理解。

function SuperType(name) { 
 this.name = name 
 this.colors = ['red', 'blue', 'green'] 
} 
SuperType.prototype.sayName = function () { 
 console.log(this.name) 
} 
function SubType(name, job) { 
 // 繼承屬性 
 SuperType.call(this, name) 
 this.job = job 
} 
// 繼承 
SubType.prototype = Object.create(SuperType.prototype) 
// 修復(fù)constructor 
SubType.prototype.constructor = SubType 
var instance = new SubType('Jiang', 'student') 
instance.sayName() 

ES6新增了一個方法,Object.setPrototypeOf,可以直接創(chuàng)建關(guān)聯(lián),而且不用手動添加constructor屬性。

// 繼承 
Object.setPrototypeOf(SubType.prototype, SuperType.prototype) 
console.log(SubType.prototype.constructor === SubType) // true 

以上所述是小編給大家介紹的JavaScript的六種繼承方式(推薦),希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!

相關(guān)文章

  • uniapp存儲數(shù)據(jù)到本地文件及讀取本地文件數(shù)據(jù)代碼示例

    uniapp存儲數(shù)據(jù)到本地文件及讀取本地文件數(shù)據(jù)代碼示例

    這篇文章主要給大家介紹了關(guān)于uniapp存儲數(shù)據(jù)到本地文件及讀取本地文件數(shù)據(jù)的相關(guān)資料,在開發(fā)uniapp應(yīng)用時,我們常常需要使用本地存儲來保存一些數(shù)據(jù),比如用戶登錄信息、設(shè)置項等,本文通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-09-09
  • 微信小程序虛擬列表的應(yīng)用實(shí)例

    微信小程序虛擬列表的應(yīng)用實(shí)例

    虛擬列表不是什么神秘的東西,下面這篇文章主要給大家介紹了關(guān)于微信小程序虛擬列表的應(yīng)用實(shí)例,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2021-12-12
  • webpack本地開發(fā)環(huán)境無法用IP訪問的解決方法

    webpack本地開發(fā)環(huán)境無法用IP訪問的解決方法

    下面小編就為大家分享一篇webpack本地開發(fā)環(huán)境無法用IP訪問的解決方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-03-03
  • js中url對象化管理分析

    js中url對象化管理分析

    這篇文章主要介紹了js中url對象化管理的相關(guān)知識以及用法介紹,有需要的朋友跟著小編一起學(xué)習(xí)下。
    2017-12-12
  • three.js 入門案例詳解

    three.js 入門案例詳解

    本篇文章主要介紹了three.js 入門案例詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-01-01
  • 使用Echarts繪制一個多組折線圖

    使用Echarts繪制一個多組折線圖

    這篇文章主要給大家介紹了關(guān)于使用Echarts繪制一個多組折線圖的相關(guān)資料,Echarts是一個功能強(qiáng)大的可視化庫,可以用來繪制各種類型的圖表,包括多組折線圖,需要的朋友可以參考下
    2023-09-09
  • Js 控制表單域代碼

    Js 控制表單域代碼

    js改變下拉框的顯示等實(shí)現(xiàn)代碼。
    2009-05-05
  • 一篇文章帶你學(xué)會JavaScript計時事件

    一篇文章帶你學(xué)會JavaScript計時事件

    JS可以實(shí)現(xiàn)很多java代碼不易完成的功能,下面這篇文章主要給大家介紹了關(guān)于如何通過一篇文章帶你學(xué)會JavaScript計時事件的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-11-11
  • 前端Token?組成及生成方法示例詳解

    前端Token?組成及生成方法示例詳解

    這篇文章主要為大家介紹了前端Token?組成及生成方法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • 淺析創(chuàng)建javascript對象的方法

    淺析創(chuàng)建javascript對象的方法

    下面小編就為大家?guī)硪黄獪\析創(chuàng)建javascript對象的方法。小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-05-05

最新評論

辉南县| 咸阳市| 浦东新区| 运城市| 鹿泉市| 吴忠市| 子洲县| 晴隆县| 酒泉市| 泸溪县| 阜南县| 石泉县| 永城市| 溧阳市| 临沧市| 资溪县| 胶州市| 交城县| 九龙坡区| 云霄县| 青铜峡市| 拉孜县| 交城县| 宜春市| 鹤庆县| 大兴区| 来安县| 汉源县| 保定市| 铜陵市| 仙桃市| 芒康县| 观塘区| 玉田县| 绥滨县| 临夏县| 体育| 东乌珠穆沁旗| 巴林左旗| 永城市| 县级市|