淺談JavaScript的幾種繼承實(shí)現(xiàn)方式
當(dāng)前需求: 實(shí)現(xiàn) Student 繼承自 Person
如果手動(dòng)實(shí)現(xiàn)繼承效果, Person和Student分別寫自己的屬性和方法, 兩個(gè)構(gòu)造函數(shù)之間沒有任何關(guān)聯(lián)
- 代碼編寫繁瑣
- 可維護(hù)性低
構(gòu)造函數(shù)Person
function Person(name, age, height, address) {
this.age = age
this.height = height
this.address = address
}
Person.prototype.running = function() {
console.log("running~")
}
Person.prototype.eating = function() {
console.log("eating~")
}構(gòu)造函數(shù)Student
function Student(name, age, height, address, sno, score) {
this.age = age
this.height = height
this.address = address
this.sno = sno
this.score = score
}
Student.prototype.running = function() {
console.log("running~")
}
Student.prototype.eating = function() {
console.log("eating~")
}
Student.prototype.studying = function() {
console.log("studying~")
}內(nèi)存圖

希望滿足的條件功能
Student構(gòu)造函數(shù)滿足以下條件
- 能夠重寫繼承的方法, 但不修改Person原型上的方法.
- 能夠增加方法, 但不會(huì)影響Person原型上的方法.
Student構(gòu)建出的實(shí)例對(duì)象滿足以下條件
- 有name, age, height, address屬性, 并且擴(kuò)充sno和score. 作為自己獨(dú)立的屬性.
- 繼承running, eating方法, 和Person實(shí)例對(duì)象的方法有相同的引用.
利用原形鏈實(shí)現(xiàn)方法的繼承
方式1: 子類原型指向父類原型
function Student(age, height, address, sno, score) {
this.age = age
this.height = height
this.address = address
this.sno = sno
this.score = score
}
+ Stuednt.prototype = Person.prototype內(nèi)存圖

缺點(diǎn)
父類和子類共享通一個(gè)原型對(duì)象, 修改了任意一個(gè), 另外一個(gè)也被修改
方式2 子類原型指向父類實(shí)例對(duì)象
function Student(sno, score) {
this.sno = sno
this.score = score
}
+ var p = new Person()
+ Student.prototype = p內(nèi)存圖

缺點(diǎn)
- 屬性放在了原型上, 無法通過打印查看.
- 創(chuàng)建的多個(gè)實(shí)例對(duì)象, 繼承的屬性不互相獨(dú)立, 一個(gè)實(shí)例對(duì)象修改屬性影響其他的實(shí)例對(duì)象
- 要new一個(gè)實(shí)例, 怪怪怪怪怪怪
借用構(gòu)造函數(shù)繼承
方式3 組合繼承
function Person(name, age, height, address) {
this.name = name
this.age = age
this.height = height
this.address = address
}
Person.prototype.running = ...
function Student(age, height, address, sno, score) {
+ Person.call(this, age, height, address)
this.sno = sno
this.score = score
}
Student.prototype = new Person()內(nèi)存圖

優(yōu)點(diǎn)
解決之前的硬性問題, 實(shí)例對(duì)象屬性獨(dú)立, 屬性放在對(duì)象內(nèi)而不是原型上.
缺點(diǎn)
- 調(diào)用兩次父類的構(gòu)造方法, 性能浪費(fèi)
Student.prototype = new Person()第一次Person.call(this)第二次
- 調(diào)用兩次構(gòu)造方法, 導(dǎo)致子類創(chuàng)建的實(shí)例對(duì)象上, 保留了兩份父類的屬性
- 一份在實(shí)例對(duì)象的
__proto__上, new時(shí)產(chǎn)生的 - 一份在實(shí)例對(duì)象上, 通過借用構(gòu)造方法call得到
- 一份在實(shí)例對(duì)象的
寄生式繼承
思路
屬性的繼承已經(jīng)解決, 通過Person.call(this) 解決.
方法的繼承未解決, 需要找到 Student.prototype = new Person() 的替代方案
思路1
var obj = {}
obj.__proto__ = Person.prototype
Student.prototype = obj
// __proto__為瀏覽器增加的屬性, 解決瀏覽器兼容性問題可以改為
var obj = {}
Object.setPrototypeOf(obj, Person.prototype)
Student.prototype = obj思路2
兼容所有瀏覽器 解決老版本瀏覽器不支持setPrototypeOf
function F() {}
F.prototype = Person.prototype
Student.prototype = new F()思路3
Object.create() 傳入一個(gè)對(duì)象作為參數(shù), 并返回一個(gè)對(duì)象, 返回的對(duì)象的原型為傳入對(duì)象
var obj = Object.create(Person.prototype) Student.prototype = obj
最終 方式4: 寄生組合式繼承
// 工具函數(shù)
// 創(chuàng)建對(duì)象的過程
function createObject(proto) {
function F() {}
F.prototype = proto
return new F()
}
// 將Subtype和Supertype聯(lián)系在一起
// 寄生式函數(shù)
function inherit(Subtype, Supertype) {
Subtype.prototype = createObject(Supertype.prototype)
Object.defineProperty(Subtype.prototype, "constructor", {
enumerable: false,
configurable: true,
writable: true,
value: Subtype
})
}
function Student(age, height, sno, score) {
Person.call(this, age, height)
this.sno = sno
this.score = score
}
+ inherit(Student, Person)
// 使用方法
Student.prototype.studying = function() {
console.log("studying")
}?? 使用Person.call實(shí)現(xiàn)屬性的繼承
?? 使用inherit實(shí)現(xiàn)方法的繼承
createObject使Student.prototype指向Person的prototype, 但中間多一個(gè)構(gòu)造函數(shù)F(), 解決方式1 的問題Object.defineProperty實(shí)現(xiàn)Student.prototype的constructor屬性指回Student構(gòu)造函數(shù).內(nèi)存圖

附: 擴(kuò)充createObject
最初的設(shè)計(jì)思想, 是為了實(shí)現(xiàn)對(duì)象的繼承, 所以有了以下的代碼
createObject只能夠做到構(gòu)造一個(gè)有原型的空對(duì)象, 現(xiàn)在想要讓構(gòu)造的對(duì)象也有屬性
createInfo(proto, age, height) {
const newObj = this.createObject(proto)
newObj.age = age
newObj.height = height
return newObj
}到此這篇關(guān)于淺談JavaScript的幾種繼承實(shí)現(xiàn)方式的文章就介紹到這了,更多相關(guān)JavaScrip 繼承內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript詳細(xì)分析數(shù)據(jù)類型和運(yùn)算符
這篇文章主要介紹了JavaScript數(shù)據(jù)類型和運(yùn)算符案例,結(jié)合實(shí)例形式分析了JavaScript數(shù)據(jù)類型和運(yùn)算符特性與相關(guān)操作技巧,需要的朋友可以參考下2022-07-07
使用JavaScript實(shí)現(xiàn)隨機(jī)曲線之間進(jìn)行平滑切換
今天,我運(yùn)用拉格朗日插值法繪制了一條曲線,然而,我并未止步于靜態(tài)展示,而是引入了一個(gè)定時(shí)器,每隔一段時(shí)間便對(duì)曲線上的點(diǎn)進(jìn)行動(dòng)態(tài)更新,從而賦予曲線生命般的動(dòng)態(tài)變化,本文介紹了使用JavaScript實(shí)現(xiàn)隨機(jī)曲線之間進(jìn)行平滑切換,感興趣的朋友可以參考下2024-11-11
JS生成不重復(fù)的隨機(jī)數(shù)組的簡(jiǎn)單實(shí)例
下面小編就為大家?guī)硪黄狫S生成不重復(fù)的隨機(jī)數(shù)組的簡(jiǎn)單實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-07-07
js判斷請(qǐng)求的url是否可訪問,支持跨域判斷的實(shí)現(xiàn)方法
下面小編就為大家?guī)硪黄猨s判斷請(qǐng)求的url是否可訪問,支持跨域判斷的實(shí)現(xiàn)方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-09-09
javascript while語句和do while語句的區(qū)別分析
這篇文章通過實(shí)例代碼較詳細(xì)的給大家介紹了javascript while語句和do while語句的區(qū)別,感興趣的朋友一起看看吧2007-12-12
詳解JavaScript原生封裝ajax請(qǐng)求和Jquery中的ajax請(qǐng)求
在本篇文章中我們總結(jié)了關(guān)于JavaScript原生封裝ajax請(qǐng)求和Jquery中的ajax請(qǐng)求的知識(shí)點(diǎn)內(nèi)容,需要的朋友們學(xué)習(xí)參考下。2019-02-02

