面向对象的三大特性: 继承 封装 多态
- JS学习:nodejs中的类定义和继承的套路在js面向对象编程中存在的问题?
- es6还是jsface库?
这是本篇要解决的问题!
1. 子类override基类同名方法时出现问题
原本要继续写渲染器方面的东西,但是在过程中遇到一个问题:根据JS学习:nodejs中的类定义和继承的套路的套路,发现一个致命的问题,无法对子类进行override,具体代码如下:
父类的render方法,绘制背景
BLFBaseSprite.prototype.render = function(render) {
render.drawGrid('black', 'white', 10, 10);
}
子类override父类render方法,增加绘制文字
BLFBaseSprite.prototype.render = function(render) {
render.drawGrid('black', 'white', 10, 10);
render.drawText(10, 10, 'blue', "随风而行之青衫磊落险峰行测试RenderSurface");
}
测试代码:(创建的是BLFBaseSprite,原本是没有文字的,但是实际却显示了文字)
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext('2d');
var render = new BLFRender(context);
var base= BLFBaseSprite();
base.render(render);
出问题啦!!!
原因: 是因为inherits函数中子类和父类的prototype指向的对象是同一个,共享了同一个prototype
也不想多花时间在这方面,于是决定选择是使用es6还是jsface库来进行js面向对象方式的编程。至于说typescript,是我非常喜欢的一门语言,但是客户端编程,就不选他了。
2. 测试es6和jsface面向对象编程的能力(继承 封装 多态)。
继承(包含子类覆写父类方法[override],以及子类调用父类方法)
jsface版本:
<script>
//Class方法1
var Base = Class({
constructor: function(name) {
this.name = name;
},
toString: function() {
return this.name;
}
});
//Class重载方法进行继承
var Child = Class(Base, {
//构造函数增加一个id参数
constructor: function(id, name) {
this.id = id;
//同时要调用基类的构造函数用于初始化name属性
Child.$super.call(this, name);
},
//override 基类方法
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); //调用基类方法
this.id = id;
}
//override基类方法
toString() {
return this.name + '_' + this.id;
}
}
var esBase = new ESBase("esBase");
var esChild = new ESChild(4321, "esChild");
alert(esBase.toString());
alert(esChild.toString());
</script>
通过使用es6和jsface,完美解决今天碰到的问题。其威力来源与子类覆写父类方法[override],以及子类调用父类方法这两个关键功能。
封装(数据隐藏)
封装最简单的解释就是java c# c++等面向对象语言中的public/protected/private这些关键词起的作用:
- public: 表明该数据成员、成员函数是对所有用户开放的,所有用户都可以直接进行调用
- private:表示私有,私有的意思就是除了class自己之外,任何人都不可以直接使用,私有财产神圣不可侵犯嘛,即便是子女,朋友,都不可以使用。
- protected:protected对于子女、朋友来说,就是public的,可以自由使用,没有任何限制,而对于其他的外部class,protected就变成private。
数据隐藏功能要在js中完美实现,难度非常大。并且感觉也没必要。数据隐藏最大的功能是隐藏实现细节,提供公开接口给第三方(面向接口编程)。js本身都是源码随意可见,因此封装数据隐藏也就不用考虑了。
为了使用代码更加清晰,可以自行设计相关规则,例如:
- 使用_开头表示protected方法或属性
- 使用__开头表示私有方法或属性
多态(函数地址运行时动态绑定)
其实多态是建立在继承和封装的基础上。强类型语言需要多态机制。js这种弱类型语言,天生就是运行时动态绑定函数地址的,因此天生支持。也不用多讲了。
反正一句话,js中只要解决继承(以及子类覆写父类方法[override],以及子类调用父类方法),我们就可以使用面向对象方式编程。也就解决了今天的一个关键问题。
3. 技术选型
测试结果(我电脑上最新版的浏览器):
浏览器 | es6 | jsface |
---|---|---|
chrome | yes | yes |
firefox | yes | yes |
opera | yes | yes |
ms edge | yes | yes |
ms ie11 | no | yes |
目前ie11还不支持es6,其他浏览器都完美支持。
从语法简明,静态函数支持,箭头函数,let/const声明等等等等角度来说,我决定选择es6了
jsface兼容性的确非常不错,但是毕竟我们是使用canvas2d webgl为主,所以还是用es6吧
我们换吧!
换es6吧!