再論Javascript的類繼承
更新時(shí)間:2011年03月05日 14:20:56 作者:
說到Javascript的類繼承,就必然離不開原型鏈,但只通過原型鏈實(shí)現(xiàn)的繼承有著不少缺陷。
無參數(shù)類繼承的問題
先看一段示例代碼,實(shí)現(xiàn)B繼承于A:
function A() {
}
A.prototype.a1 = function() {
};
function B() {
}
B.prototype = new A();
B.prototype.b1 = function() {
};
var b = new B();
alert(b.constructor == A); // true
alert(b.constructor == B); // false
這段代碼的主要問題是:
* 需要實(shí)例化A作為B的原型,此時(shí)就執(zhí)行了A的構(gòu)造函數(shù)。但按照面向?qū)ο蟮囊?guī)則,實(shí)例化B之前,B及其父類A的構(gòu)造函數(shù)都不應(yīng)該執(zhí)行。
* 更改了B的prototype,導(dǎo)致b.constructor不是B而是A。
有參類繼承的問題
假設(shè)A和B都有兩個(gè)字符串參數(shù)s1和s2,A中計(jì)算了兩段字符串的總長度,B直接以s1、s2為參數(shù)調(diào)用A:
function A(s1, s2) {
this.totalLength = s1.length + s2.length;
}
A.prototype.a1 = function() {
};
function B(s1, s2) {
}
B.prototype = new A();
B.prototype.b1 = function() {
};
new B("ab", "123");
可以看到,這段代碼中根本沒有辦法把s1和s2傳到A,而又因?yàn)閷?shí)例化A作為B的原型時(shí)沒有參數(shù),所以出現(xiàn)了異常:
s1 is undefined
解決方案
s1和s2的作用域只在B內(nèi),要把它們傳到A,就只能在B中操作,借助函數(shù)的apply方法就可以實(shí)現(xiàn)之:
function B(s1, s2) {
A.apply(this, arguments);
alert(this.totalLength);
}
接下來的問題就是如何把A的方法添加到B的原型中去。這也不難,只要遍歷A.prototype,把方法復(fù)制到B.prototype即可。要注意的是,對于同名的方法,自然是子類優(yōu)先(重載),因而不能覆蓋:
for (var m in A.prototype) {
if (!B.prototype[m]) { // 父類不能覆蓋子類的方法
B.prototype[m] = A.prototype[m];
}
}
后記
考慮到C#、Java等高級語言都拋棄了多繼承,因此,本文所討論的也只是單繼承的情況。而本文所述的繼承方法,也會(huì)寫成jRaiser的一個(gè)擴(kuò)展,遲些發(fā)布。
先看一段示例代碼,實(shí)現(xiàn)B繼承于A:
復(fù)制代碼 代碼如下:
function A() {
}
A.prototype.a1 = function() {
};
function B() {
}
B.prototype = new A();
B.prototype.b1 = function() {
};
var b = new B();
alert(b.constructor == A); // true
alert(b.constructor == B); // false
這段代碼的主要問題是:
* 需要實(shí)例化A作為B的原型,此時(shí)就執(zhí)行了A的構(gòu)造函數(shù)。但按照面向?qū)ο蟮囊?guī)則,實(shí)例化B之前,B及其父類A的構(gòu)造函數(shù)都不應(yīng)該執(zhí)行。
* 更改了B的prototype,導(dǎo)致b.constructor不是B而是A。
有參類繼承的問題
假設(shè)A和B都有兩個(gè)字符串參數(shù)s1和s2,A中計(jì)算了兩段字符串的總長度,B直接以s1、s2為參數(shù)調(diào)用A:
復(fù)制代碼 代碼如下:
function A(s1, s2) {
this.totalLength = s1.length + s2.length;
}
A.prototype.a1 = function() {
};
function B(s1, s2) {
}
B.prototype = new A();
B.prototype.b1 = function() {
};
new B("ab", "123");
可以看到,這段代碼中根本沒有辦法把s1和s2傳到A,而又因?yàn)閷?shí)例化A作為B的原型時(shí)沒有參數(shù),所以出現(xiàn)了異常:
復(fù)制代碼 代碼如下:
s1 is undefined
解決方案
s1和s2的作用域只在B內(nèi),要把它們傳到A,就只能在B中操作,借助函數(shù)的apply方法就可以實(shí)現(xiàn)之:
復(fù)制代碼 代碼如下:
function B(s1, s2) {
A.apply(this, arguments);
alert(this.totalLength);
}
接下來的問題就是如何把A的方法添加到B的原型中去。這也不難,只要遍歷A.prototype,把方法復(fù)制到B.prototype即可。要注意的是,對于同名的方法,自然是子類優(yōu)先(重載),因而不能覆蓋:
復(fù)制代碼 代碼如下:
for (var m in A.prototype) {
if (!B.prototype[m]) { // 父類不能覆蓋子類的方法
B.prototype[m] = A.prototype[m];
}
}
后記
考慮到C#、Java等高級語言都拋棄了多繼承,因此,本文所討論的也只是單繼承的情況。而本文所述的繼承方法,也會(huì)寫成jRaiser的一個(gè)擴(kuò)展,遲些發(fā)布。
相關(guān)文章
JS彈出可拖拽可關(guān)閉的div層完整實(shí)例
這篇文章主要介紹了JS彈出可拖拽可關(guān)閉的div層完整實(shí)現(xiàn)方法,包括對div彈出層的樣式及功能的實(shí)現(xiàn)技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-02-02JS實(shí)現(xiàn)瀏覽器打印、打印預(yù)覽示例
本篇文章主要介紹了JS實(shí)現(xiàn)瀏覽器打印、打印預(yù)覽示例。小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-02-02兩個(gè)JS之間的函數(shù)互相調(diào)用方式
這篇文章主要介紹了兩個(gè)JS之間的函數(shù)互相調(diào)用方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03使用Promise解決多層異步調(diào)用的簡單學(xué)習(xí)心得
下面小編就為大家?guī)硪黄褂肞romise解決多層異步調(diào)用的簡單學(xué)習(xí)心得。小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-05-05手機(jī)圖片預(yù)覽插件photoswipe.js使用總結(jié)
這篇文章主要為大家詳細(xì)總結(jié)了手機(jī)圖片預(yù)覽插件photoswipe.js使用方法,感興趣的小伙伴們可以參考一下2016-08-08為什么JavaScript中0.1 + 0.2 != 0.3
這篇文章主要給大家介紹了關(guān)于為什么JavaScript中0.1 + 0.2 != 0.3的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12微信小程序?qū)崿F(xiàn)類似微信點(diǎn)擊語音播放效果
這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)類似微信點(diǎn)擊語音播放效果,不會(huì)互相干擾播放狀態(tài),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-07-07