JavaScript實(shí)現(xiàn)繼承的7種方式總結(jié)
什么是繼承
用官方點(diǎn)的話(huà)講繼承是面向?qū)ο笕筇卣髦唬梢允沟米宇?lèi)具有父類(lèi)的屬性和方法,同時(shí)還可以在子類(lèi)中重新定義以及追加屬性和方法。通俗的來(lái)說(shuō)繼承就是子類(lèi)可以從父類(lèi)那里復(fù)用一些屬性和方法,從而達(dá)到復(fù)用代碼的一個(gè)效果。
實(shí)現(xiàn)繼承的6種方式
- 原型鏈繼承
- 構(gòu)造函數(shù)繼承
- 組合繼承(偽經(jīng)典繼承)
- 原型式繼承
- 寄生式繼承
- 寄生組合式繼承
- class 類(lèi)繼承
1. 原型鏈繼承
function Person() {
this.name = 'bruce'
this.age = 18
this.gender = '男'
this.like = {
sport: 'running',
book: 'JavaScript'
}
this.getName = function() {
console.log(this.name);
}
}
function Student() {
this.school = '新華小學(xué)'
}
let s = new Student()
console.log(s.name); // 未繼承前 undefined
Student.prototype = new Person() // 繼承之后
let s1 = new Student()
s1.getName() // bruce
console.log(s1.like.book); // JavaScript
s1.like.book = 'Java' // 修改引用類(lèi)型的值
s1.name = 'jack' // 修改非引用類(lèi)型的值
console.log(s1.like.book); // Java
s1.getName() // jack
console.log('----------');
let s2 = new Student()
s2.getName() // bruce
console.log(s2.like.book); // Java所謂的原型鏈繼承,在我的理解就是子類(lèi)通過(guò)原型鏈來(lái)繼承到父類(lèi)的屬性,在上面的代碼中我們也可以看到在子類(lèi)實(shí)例s沒(méi)有繼承到父類(lèi)的屬性時(shí),子類(lèi)去訪問(wèn)父類(lèi)才有的屬性值為:undefined。
在將父類(lèi)實(shí)例對(duì)象掛載到子類(lèi)Student構(gòu)造函數(shù)的原型上面后,那么此時(shí)子類(lèi)的原型上面就有了父類(lèi)的全部屬性。因?yàn)?code>Person的實(shí)例對(duì)象被顯示的掛載到了Student的原型上面。所以子類(lèi)在繼承之后,所有實(shí)例化的子類(lèi)都擁有了跟父類(lèi)一樣的屬性,于是這樣子類(lèi)就通過(guò)原型鏈實(shí)現(xiàn)了繼承。
優(yōu)點(diǎn): 子類(lèi)可以繼承到父類(lèi)的方法。
缺點(diǎn):
- 會(huì)在子類(lèi)實(shí)例上共享父類(lèi)所有的引用類(lèi)型數(shù)據(jù),也就是子類(lèi)的原型被父類(lèi)屬性覆蓋。
- 子類(lèi)實(shí)例不能給父類(lèi)構(gòu)造函數(shù)傳參。
function Person(t) {
this.property = t
}
function Student(t) {
this.typeproperty = t
}
Student.prototype = new Person()
let s=new Student('a')
console.log(s.property) // undefined
console.log(s.typeproperty) // a
這樣子類(lèi)實(shí)例傳的參數(shù)就不能給到父類(lèi)構(gòu)造函數(shù)里面了。
2. 構(gòu)造函數(shù)繼承
function Person(name,age) {
this.name = name
this.age = age
this.like = {
sport: 'running',
book: 'JavaScript'
}
this.getName = function () {
console.log(this.name);
}
}
Person.prototype.sayHello = function () {
console.log('你好');
}
function Student(name, age,) {
Person.call(this, name, age) // 借用構(gòu)造函數(shù)
}
let s1 = new Student('bruce',18)
s1.getName() // bruce
s1.name='jack'
s1.getName() // jack
s1.like.sport='swimming'
console.log(s1.like.sport); // swimming
console.log('------');
let s2=new Student('lucy',19)
s2.getName() // lucy
console.log(s2.like.sport); // running
構(gòu)造函數(shù)繼承就是使用強(qiáng)制改變 this 指向,借用一個(gè)構(gòu)造函數(shù)繼承。相較于原型鏈繼承,構(gòu)造函數(shù)繼承不會(huì)共享父類(lèi)上的引用類(lèi)型數(shù)據(jù),不會(huì)互相影響。
缺點(diǎn):1.不能訪問(wèn)到父類(lèi)原型屬性上面的方法和參數(shù),即 Person.prototype 上的都不能訪問(wèn)到。
Person.prototype.sayHello = function () { // 在 Person 的原型上面加一個(gè)方法
console.log('你好');
}
let s1 = new Student('bruce',18)
s1.sayHello() // s1.sayHello is not a function
3. 組合繼承(偽經(jīng)典繼承)
相較于原型鏈繼承,構(gòu)造函數(shù)繼承好像已經(jīng)非常完美了,但是它還是存在著一個(gè)最大的缺點(diǎn)就是:不能繼承到父類(lèi)的原型上面的屬性。但是原型鏈繼承就好像沒(méi)有這個(gè)問(wèn)題,如果將這兩個(gè)繼承方式組合起來(lái)搭配使用是不是就能解決掉所有問(wèn)題,于是這就有了組合繼承。
function Person(name, age) {
this.name = name
this.age = age
this.like = {
sport: 'running',
book: 'JavaScript'
}
this.getName = function () {
console.log(this.name);
}
}
Person.prototype.sayHello = function () {
console.log('你好');
}
function Student(name, age) {
Person.call(this, name, age) // 構(gòu)造函數(shù)繼承
}
Student.prototype = new Person() // 原型鏈繼承
let s1 = new Student('bruce', 18)
s1.sayHello() // 你好
console.log(s1);
上面先在子類(lèi)內(nèi)使用構(gòu)造函數(shù)繼承將父類(lèi)的顯示屬性?huà)燧d到子類(lèi)上面,此時(shí)仍然存在著構(gòu)造函數(shù)繼承中子類(lèi)不能訪問(wèn)到父類(lèi)原型上面屬性的缺點(diǎn)。
所以下面配合原型鏈繼承將父類(lèi)實(shí)例掛載到子類(lèi)的原型上,此時(shí)子類(lèi)就可以訪問(wèn)父類(lèi)的原型上的屬性,同時(shí)構(gòu)造函數(shù)繼承將子類(lèi)的原型被父類(lèi)屬性覆蓋的問(wèn)題解決。
組合繼承將前面兩種繼承的缺點(diǎn)都補(bǔ)全了,但是它也有缺點(diǎn):
不足:重復(fù)調(diào)用兩次父類(lèi)函數(shù)。

4. 原型式繼承
function object(o){ // 參數(shù)為父類(lèi)
function F(){}
F.prototype=o
return new F()
}
const person={
sex:'man',
age:20
}
let realPerson=object(person)
console.log(realPerson.sex);// man
通過(guò)在一個(gè)構(gòu)造函數(shù)的原型上掛載父類(lèi),此時(shí)再將這個(gè)掛載了父類(lèi)的構(gòu)造函數(shù)實(shí)例返回出來(lái),那么這個(gè)實(shí)例的隱式原型就為這個(gè)父類(lèi),所以此時(shí)子類(lèi)實(shí)例對(duì)象可以訪問(wèn)到父類(lèi)上的屬性,這就是原型式繼承。這個(gè)看起來(lái)跟理解起來(lái)是不是跟原型鏈繼承很像,也挺好理解的。
缺點(diǎn): 如果父類(lèi)屬性有引用類(lèi)型,那么這個(gè)引用類(lèi)型也會(huì)被共享出來(lái)。
function object(o){
function F(){}
F.prototype=o
return new F()
}
const person={
sex:'man',
age:20,
like:{
sports:'running'
}
}
let r1=object(person)
console.log(r1.like);// { sports: 'running' }
let r2=object(person)
r2.like.sports='singing'
console.log(r1.like); // { sports: 'singing' }
實(shí)例化兩個(gè)不同的對(duì)象,更改 r2 的sports 屬性,結(jié)果 r1 的 sports 屬性也被修改。
5. 寄生式繼承
這種繼承方式跟原型式繼承有著異曲同工之妙,只不過(guò)可以增強(qiáng)這個(gè)父類(lèi)。其存在的缺點(diǎn)也與原型式繼承一樣。
function createPerson(original) {
var clone = Object.create(original)
clone.say = function() { // 增強(qiáng)這個(gè)對(duì)象
console.log('hello');
}
return clone
}
6.寄生組合式繼承
這個(gè)是一個(gè)比較完美的繼承方式,使用組合繼承與寄生繼承。
function Person(name, age) {
this.name = name
this.age = age
this.like = {
sport: 'running',
book: 'JavaScript'
}
this.getName = function () {
console.log(this.name);
}
}
Person.prototype.sayHello = function () {
console.log('你好');
}
function Student(name, age) {
Person.call(this, name, age) // 借用構(gòu)造函數(shù)
}
const Fn=function(){}
Fn.prototype=Person.prototype
Student.prototype = new Fn()
let s1 = new Student('bruce', 18)
s1.sayHello() // 你好
console.log(s1);
這種繼承方式結(jié)合了組合繼承,借助一個(gè)空的構(gòu)造函數(shù),將父類(lèi)的原型掛載到這個(gè)空的構(gòu)造函數(shù)上面,然后將其附在子類(lèi)的原型上面,這樣就解決了組合式繼承的缺點(diǎn)。

7.class 類(lèi)繼承
Class 可以通過(guò)extends關(guān)鍵字實(shí)現(xiàn)繼承,讓子類(lèi)繼承父類(lèi)的屬性和方法。
class Person{
constructor(name){
this.name=name
}
}
class Student extends Person{
constructor(name,age){
super(name)
this.age=age
}
}
let s=new Student('bruce',20)
console.log(s); //Student { name: 'bruce', age: 20 }以上就是JavaScript實(shí)現(xiàn)繼承的7種方式總結(jié)的詳細(xì)內(nèi)容,更多關(guān)于JavaScript繼承的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
提高網(wǎng)站性能之 如何對(duì)待JavaScript
在一個(gè)頁(yè)面中,每一個(gè)外部JavaScript 及CSS文件都會(huì)導(dǎo)致一個(gè)額外的HTTP請(qǐng)求。所以,如何合理的合并JavaScript 文件及CSS文件也是前端工程師應(yīng)該考慮的。2009-10-10
Layui實(shí)現(xiàn)主窗口和Iframe層參數(shù)傳遞
今天小編就為大家分享一篇Layui實(shí)現(xiàn)主窗口和Iframe層參數(shù)傳遞,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-11-11
JS庫(kù) Highlightjs 添加代碼行號(hào)的實(shí)現(xiàn)代碼
Highlightjs是一款優(yōu)秀的代碼高亮Js組件,可以很方便地對(duì)各種語(yǔ)言編寫(xiě)的代碼添加語(yǔ)法高亮樣式。本文重點(diǎn)給大家介紹Highlightjs 添加代碼行號(hào)的實(shí)現(xiàn)代碼,需要的朋友參考下吧2017-09-09
JS將網(wǎng)址url轉(zhuǎn)化為JSON格式的方法
這篇文章主要介紹了JS將網(wǎng)址url轉(zhuǎn)化為JSON格式的方法,需要的朋友可以參考下2018-07-07
如何使用proxy實(shí)現(xiàn)一個(gè)簡(jiǎn)單完整的MVVM庫(kù)的示例代碼
這篇文章主要介紹了如何使用proxy實(shí)現(xiàn)一個(gè)簡(jiǎn)單完整的MVVM庫(kù)的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
用javascript獲取textarea中的光標(biāo)位置
Javascript一向以他的靈活隨意而著稱(chēng),這也使得它的功能可以非常的強(qiáng)大,而由于沒(méi)有比較好的調(diào)試工具,又使得它使用起來(lái)困難重重,尤其使對(duì)于一些初學(xué)者,更是感覺(jué)到無(wú)從下手。今天探討的問(wèn)題是用javascript獲取textarea中光標(biāo)的位置。2008-05-05
echart簡(jiǎn)介_(kāi)動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了echart簡(jiǎn)介,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-08-08
Layui實(shí)現(xiàn)數(shù)據(jù)表格默認(rèn)全部顯示(不要分頁(yè))
今天小編就為大家分享一篇Layui實(shí)現(xiàn)數(shù)據(jù)表格默認(rèn)全部顯示(不要分頁(yè)),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-10-10

