上一篇中介绍了模拟类和模拟继承的多种方式,并且对各种方式做了一个简单的优缺点描述。本文主要是描述作者认为在选用哪一种方式的所考虑的一些具体方面及最终的方案。
选择基准
模拟类的代码有好几种方案,每一种都有它的优缺点。我们在选择模拟类的代码时,也需要综合考虑这些方面,并确定适合的方案。这里列举了笔者认为需要注意的一些要点。
1. 尽量不对JavaScript内置的对象进行修改(如在Function类上添加方法)
不可否认,直接在JavaScript内置类上增加方法是一个很常用的方式,最常使用的几个类就是Object,Function和String。如经常会看到的在String上增加trim,ltrim,rtrim方法的。
但是一个页面可能会用到很多人写的JS代码,如果大家命名有冲突的话,还是会发生一些障害的。
2. 模拟出来的类要尽量和JavaScript Core中所定义的内部类(具体见图1)一样 ,使得我们模拟的类可以像这些内部类一样正常的使用。
--使用new操作符构造对象,而不是使用其他的方法返回对象,比如说factory。
图1. JavaScript Core中的15个内置类的继承结构
3. instanceof操作符可以正常使用
关于instanceof操作符的作用,我们可以从以下代码看出来。instanceof操作符是可以识别出一个对象的类型,包括父类,祖父类。。直到Object类为止。而这个是通过JavaScript的原型链机制来实现的,所以我们在选用方案的时候就必须要使用原型链为基础的方式。
4. Object.constructor可以正常使用
从字面上理解,对象的constructor属性指向构造这个对象实例的类的构造函数。但是如果使用原型链的方式来实现类继承的话,子类的实例的constructor却是指向父类的构造函数。
所以我们可以得出,对象的constructor属性并非指向其构造器,而是指向其构造器的prototype属性的constructor属性。
5. 私有变量还是公有变量
按照OO的思想,数据是要封装的,所以数据不应该可以被直接访问到,而是要靠类提供的方法来访问。按照这种思路,无疑我们应该选用私有变量。但是现在已知的模拟私有变量的方法有两个缺点。一是使用prototype的方式定义的public方法无法访问到私有变量;二是私有变量是使用了闭包机制来实现的,可能会造成内存泄漏(浏览器处理机制的不良或者开发者的代码miss)。
Douglas Crockford在他的Private Members in JavaScript 中提出了私有变量的实现方法。
根据以上分析,个人认为使用公有变量更好一点。对于真正的私有变量通过在变量名之前加一个"_"来表示。制定这样的编码规范之后,使用者就可以知道这个变量是私有的,不能够直接调用。
6. this形式声明公有方法还是prototype的形式
声明公有方法的方式有两种。一种是在构造函数中使用this来声明,这种方式的好处是可以访问私有变量,但是在内存占用上有一点损耗;另外一种是使用prototype的形式声明,这种方式最大限度的节约了内存空间,无法访问私有变量。
根据我所了解到的一些模拟类的方式,基本上都是推荐prototype形式的,并且我们上面也分析不使用私有变量,那么选择prototype就是最佳方法了。
总结
根据以上的总体分析,类的模拟方式,选择构造函数和原型链的组合方式。而类的继承,则选择寄生组合式继承方式。再加以一定的编码规范的制约,差不多是足够的。
当然了,这样的选择只是相对来说最通用的选择,但并不是适合所有项目,所有需求的。请各位在做决策的时候根据自己的项目需求来筛选。
参考资料
1. Douglas Crockford的个人网站:
http://www.crockford.com/
2. Private Members in JavaScript:
http://www.crockford.com/javascript/private.html
3. JavaScript constructor和instanceof,JSOO中的一对欢喜冤家: http://www.jb51.net/article/18254.htm
4. Object instanceof Function 还是 Function instance of Object,是真是假,一一道来:
http://www.cnblogs.com/objectorl/archive/2010/01/11/Object-instancof-Function-clarification.html