淺談JavaScript的幾種繼承實(shí)現(xiàn)方式
當(dāng)前需求: 實(shí)現(xiàn) Student 繼承自 Person
如果手動實(shí)現(xiàn)繼承效果, Person和Student分別寫自己的屬性和方法, 兩個構(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原型上的方法.
- 能夠增加方法, 但不會影響Person原型上的方法.
Student構(gòu)建出的實(shí)例對象滿足以下條件
- 有name, age, height, address屬性, 并且擴(kuò)充sno和score. 作為自己獨(dú)立的屬性.
- 繼承running, eating方法, 和Person實(shí)例對象的方法有相同的引用.
利用原形鏈實(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)
父類和子類共享通一個原型對象, 修改了任意一個, 另外一個也被修改
方式2 子類原型指向父類實(shí)例對象
function Student(sno, score) {
this.sno = sno
this.score = score
}
+ var p = new Person()
+ Student.prototype = p內(nèi)存圖

缺點(diǎn)
- 屬性放在了原型上, 無法通過打印查看.
- 創(chuàng)建的多個實(shí)例對象, 繼承的屬性不互相獨(dú)立, 一個實(shí)例對象修改屬性影響其他的實(shí)例對象
- 要new一個實(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í)例對象屬性獨(dú)立, 屬性放在對象內(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í)例對象上, 保留了兩份父類的屬性
- 一份在實(shí)例對象的
__proto__上, new時產(chǎn)生的 - 一份在實(shí)例對象上, 通過借用構(gòu)造方法call得到
- 一份在實(shí)例對象的
寄生式繼承
思路
屬性的繼承已經(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() 傳入一個對象作為參數(shù), 并返回一個對象, 返回的對象的原型為傳入對象
var obj = Object.create(Person.prototype) Student.prototype = obj
最終 方式4: 寄生組合式繼承
// 工具函數(shù)
// 創(chuàng)建對象的過程
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ò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)對象的繼承, 所以有了以下的代碼
createObject只能夠做到構(gòu)造一個有原型的空對象, 現(xiàn)在想要讓構(gòu)造的對象也有屬性
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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript中數(shù)據(jù)類型轉(zhuǎn)換總結(jié)
在js中,數(shù)據(jù)類型轉(zhuǎn)換分為顯式數(shù)據(jù)類型轉(zhuǎn)換和隱式數(shù)據(jù)類型轉(zhuǎn)換。本文將對此進(jìn)行介紹,具有一定的參考價值,需要的朋友一起來看下吧2016-12-12
微信小程序定義和調(diào)用全局變量globalData的實(shí)現(xiàn)
這篇文章主要介紹了微信小程序定義和調(diào)用全局變量globalData的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11
Bootstrap 設(shè)置datetimepicker在屏幕上面彈出設(shè)置方法
datetimepicker默認(rèn)是在輸入框下面彈出的,但是遇到輸入框在屏幕下面時,日期選擇框會有一部分在屏幕下面,顯示不了,因此需要能夠從上面彈出,下面小編給大家介紹下Bootstrap 設(shè)置datetimepicker在屏幕上面彈出的設(shè)置方法2017-03-03
JavaScript 實(shí)現(xiàn)拖拽效果組件功能(兼容移動端)
這篇文章主要介紹了JavaScript 實(shí)現(xiàn)拖拽效果組件功能(兼容移動端),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-11-11
JS實(shí)現(xiàn)頁面中所有img對象添加onclick事件及新窗口查看圖片的方法
這篇文章主要介紹了JS實(shí)現(xiàn)頁面中所有img對象添加onclick事件及新窗口查看圖片的方法,涉及JS頁面元素遍歷及屬性動態(tài)操作相關(guān)技巧,需要的朋友可以參考下2016-12-12

