像进度条这样的小组件,我们应该尽量将其封装到一个全局变量中,如:var lightLoader = function(e) { }; 。源码中传入的参数是一个canvas和宽高,但是假如我们要设置进度条的属性的时候,就必须到源码里面去改动了,这样的话可复用性就打了个打折扣。还好,与进度条相关的属性都被封装到了全局变量的属性中,要改动的话实例化后直接改lightLoade.属性也可以使用。
设置传入一个对象的话,后续要对这个组件进行扩展或者改动的时候,那对象参数的便利性就体现得淋漓尽致了。
比如我要扩展一个进度条的宽度:this.loaderHeight = opt.loaderHeight ? opt.loaderHeight : 20; 就完事了(实参的类型和值的安全性暂不讨论哈!)。原来的var lightLoader = function(c, cw, ch){} 如果要扩展一个进度条的宽度,想当然地我们可以写出 var lightLoader = function(c, cw, ch, lw) { this.loaderHeight = lw ? lw : 20 },但是麻烦的是,当我们new lightLoader(c, 20)的时候,20并没有传到给宽度啊。因为参数是有顺序的,而对象的属性则安全得多。
(二) 定义对象的方式源码里面定义lightLoader时使用的是经典的构造函数的方式,将属性和函数都放在构造函数中,而粒子Particle的方法则是放在Particle的原型中定义的。这很关键!
经典构造函数带来的问题可以自行百度,博客园上介绍也非常多,一搜一百页。简单来说就是构造函数内部的所有函数和属性都会被复制到每个实例中,比如说我通过构造函数创建了5个实例,那在内存中就有5份副本存在。但是很明显,方法(不习惯说函数。。。)不应该被复制5份,而应该是5个实例共享一个方法即可。所以,目前推荐的是使用混合模式定义对象:属性放在构造函数中,方法放在原型中。对于数量较大(比如说本例中的粒子),那方法甚至属性都应该放在原型中,以减少内存消耗,提高动画流畅度。
虽然源码那样写了, 但是我还是觉得lightLoader对象的方法也应该放到原型中,这是也是个代码规范的问题。
(三)封装问题源码中所有属性都被定义为this.**,也就是说都暴露给外界了。这些属性都是跟效果相关的,很多属性需要看着效果调试出来的。暴露出来的好处就是调试的时候可以在运行时动态改变相应的值,观察效果的变化,非常方便。你们感受一下:
但并不是所有属性都应该被暴露出来的,哪些需要暴露,哪些需要隐藏这个要看具体场景了。另外私有成员的命名潜规则(←.←)是前面加_,私有属性和私有方法都应该这样命名,这样同类们一看到就懂啦。
封装的另外一个方面是要与DOM对象松耦合,一个组件假如跟其他元素的联系很紧密的话,移植性就非常差了。这一点暂时我还没太多体会,不敢妄议。
就说到这里啦,看起来不是很有料呢。。。所以,还是补张图片丰满一下吧~码字不易,顺手点赞哈!
(图片出处:著名摄影师 小张同学,转载请注明)
原创文章,转载请注明出处!本文链接: