面向?qū)ο蟮娜筇匦? 繼承 封裝 多態(tài)
- JS學(xué)習(xí):nodejs中的類(lèi)定義和繼承的套路在js面向?qū)ο缶幊讨写嬖诘膯?wèn)題?
- es6還是jsface庫(kù)?
這是本篇要解決的問(wèn)題掀亩!
1. 子類(lèi)override基類(lèi)同名方法時(shí)出現(xiàn)問(wèn)題
原本要繼續(xù)寫(xiě)渲染器方面的東西,但是在過(guò)程中遇到一個(gè)問(wèn)題:根據(jù)JS學(xué)習(xí):nodejs中的類(lèi)定義和繼承的套路的套路,發(fā)現(xiàn)一個(gè)致命的問(wèn)題凡简,無(wú)法對(duì)子類(lèi)進(jìn)行override逼友,具體代碼如下:
父類(lèi)的render方法,繪制背景
BLFBaseSprite.prototype.render = function(render) {
render.drawGrid('black', 'white', 10, 10);
}
子類(lèi)override父類(lèi)render方法秤涩,增加繪制文字
BLFBaseSprite.prototype.render = function(render) {
render.drawGrid('black', 'white', 10, 10);
render.drawText(10, 10, 'blue', "隨風(fēng)而行之青衫磊落險(xiǎn)峰行測(cè)試RenderSurface");
}
測(cè)試代碼:(創(chuàng)建的是BLFBaseSprite帜乞,原本是沒(méi)有文字的,但是實(shí)際卻顯示了文字)
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext('2d');
var render = new BLFRender(context);
var base= BLFBaseSprite();
base.render(render);
出問(wèn)題啦?鹁臁@枇摇!
原因: 是因?yàn)閕nherits函數(shù)中子類(lèi)和父類(lèi)的prototype指向的對(duì)象是同一個(gè)匀谣,共享了同一個(gè)prototype
也不想多花時(shí)間在這方面照棋,于是決定選擇是使用es6還是jsface庫(kù)來(lái)進(jìn)行js面向?qū)ο蠓绞降木幊獭V劣谡f(shuō)typescript武翎,是我非常喜歡的一門(mén)語(yǔ)言烈炭,但是客戶(hù)端編程,就不選他了宝恶。
2. 測(cè)試es6和jsface面向?qū)ο缶幊痰哪芰?繼承 封裝 多態(tài))符隙。
繼承(包含子類(lèi)覆寫(xiě)父類(lèi)方法[override],以及子類(lèi)調(diào)用父類(lèi)方法)
jsface版本:
<script>
//Class方法1
var Base = Class({
constructor: function(name) {
this.name = name;
},
toString: function() {
return this.name;
}
});
//Class重載方法進(jìn)行繼承
var Child = Class(Base, {
//構(gòu)造函數(shù)增加一個(gè)id參數(shù)
constructor: function(id, name) {
this.id = id;
//同時(shí)要調(diào)用基類(lèi)的構(gòu)造函數(shù)用于初始化name屬性
Child.$super.call(this, name);
},
//override 基類(lèi)方法
toString: function() {
return this.name + '-' + this.id;
}
});
var base = new Base("base");
var child = new Child(1234, "child");
alert(base.toString());
alert(child.toString());
</script>
es6版本:
<script>
class ESBase {
constructor(name) {
this.name = name;
}
toString() {
return this.name;
}
}
class ESChild extends ESBase {
constructor(id, name) {
super(name); //調(diào)用基類(lèi)方法
this.id = id;
}
//override基類(lèi)方法
toString() {
return this.name + '_' + this.id;
}
}
var esBase = new ESBase("esBase");
var esChild = new ESChild(4321, "esChild");
alert(esBase.toString());
alert(esChild.toString());
</script>
通過(guò)使用es6和jsface,完美解決今天碰到的問(wèn)題垫毙。其威力來(lái)源與子類(lèi)覆寫(xiě)父類(lèi)方法[override],以及子類(lèi)調(diào)用父類(lèi)方法這兩個(gè)關(guān)鍵功能霹疫。
封裝(數(shù)據(jù)隱藏)
封裝最簡(jiǎn)單的解釋就是java c# c++等面向?qū)ο笳Z(yǔ)言中的public/protected/private這些關(guān)鍵詞起的作用:
- public: 表明該數(shù)據(jù)成員、成員函數(shù)是對(duì)所有用戶(hù)開(kāi)放的综芥,所有用戶(hù)都可以直接進(jìn)行調(diào)用
- private:表示私有丽蝎,私有的意思就是除了class自己之外,任何人都不可以直接使用膀藐,私有財(cái)產(chǎn)神圣不可侵犯嘛征峦,即便是子女,朋友栏笆,都不可以使用。
- protected:protected對(duì)于子女蛉加、朋友來(lái)說(shuō)缸逃,就是public的针饥,可以自由使用,沒(méi)有任何限制需频,而對(duì)于其他的外部class,protected就變成private昭殉。
數(shù)據(jù)隱藏功能要在js中完美實(shí)現(xiàn)藐守,難度非常大。并且感覺(jué)也沒(méi)必要蹂风。數(shù)據(jù)隱藏最大的功能是隱藏實(shí)現(xiàn)細(xì)節(jié)卢厂,提供公開(kāi)接口給第三方(面向接口編程)。js本身都是源碼隨意可見(jiàn)惠啄,因此封裝數(shù)據(jù)隱藏也就不用考慮了。
為了使用代碼更加清晰融柬,可以自行設(shè)計(jì)相關(guān)規(guī)則,例如:
- 使用_開(kāi)頭表示protected方法或?qū)傩?/li>
- 使用__開(kāi)頭表示私有方法或?qū)傩?/li>
多態(tài)(函數(shù)地址運(yùn)行時(shí)動(dòng)態(tài)綁定)
其實(shí)多態(tài)是建立在繼承和封裝的基礎(chǔ)上粒氧。強(qiáng)類(lèi)型語(yǔ)言需要多態(tài)機(jī)制棚品。js這種弱類(lèi)型語(yǔ)言,天生就是運(yùn)行時(shí)動(dòng)態(tài)綁定函數(shù)地址的铜跑,因此天生支持。也不用多講了掷空。
反正一句話(huà)囤锉,js中只要解決繼承(以及子類(lèi)覆寫(xiě)父類(lèi)方法[override],以及子類(lèi)調(diào)用父類(lèi)方法),我們就可以使用面向?qū)ο蠓绞骄幊坦俚亍R簿徒鉀Q了今天的一個(gè)關(guān)鍵問(wèn)題。
3. 技術(shù)選型
測(cè)試結(jié)果(我電腦上最新版的瀏覽器):
瀏覽器 | es6 | jsface |
---|---|---|
chrome | yes | yes |
firefox | yes | yes |
opera | yes | yes |
ms edge | yes | yes |
ms ie11 | no | yes |
目前ie11還不支持es6,其他瀏覽器都完美支持赤炒。
從語(yǔ)法簡(jiǎn)明亏较,靜態(tài)函數(shù)支持,箭頭函數(shù)遵岩,let/const聲明等等等等角度來(lái)說(shuō)巡通,我決定選擇es6了
jsface兼容性的確非常不錯(cuò)尘执,但是畢竟我們是使用canvas2d webgl為主,所以還是用es6吧
我們換吧正卧!
換es6吧跪解!