一、前言
第一次来到蓝色理想的感觉就是这里的规定好多哦,比如我在置顶贴自报家门说我是无忧脚本论坛的泣红亭就被罚写三篇文章,还特别要求那文章必须没有在无忧脚本发过的,郁闷极了,真有这种规定吗?呵呵。不过入乡随俗,仔细看了一下这里比较热门的话题,发现无忧的两个热门话题在这里都有谈到,一个是幻宇的星际JS版,另一个是万常华的JSVM。
我看大家可能对幻宇的星际更感兴趣一点,但我却挑了JSVM,为什么呢?
首先,星际是还没有到那种程度可以实际应用,而且开发的工作也轮不到我们,它是幻宇个人或者他的Team在独立开发的,而JSVM任何人只要掌握了它的使用方法就可以应用在网站中,甚至你还可以自己动手为它扩充类库!这一点是非常重要的,我觉得这才是真正的代码开放。
其实许多人对JSVM不大感兴趣也是可以理解的,老实说,要理解它的思想是很难的,因为它是属于Web底层的开发,但如果你理解了它的思想,你会发现在JS领域突然出现了一片新的天地,当我看到这片天地的时候,很兴奋,整整看了两个通宵的JSVM代码,然后自己动手编写出一个类似的项目,我称我编写的项目叫做JsPackage,已经正式应用在我的个人主页上了,不过没有拿出来公布,一方面是因为JSVM比我写的好,没有必要拿出来出丑;第二个方面是同类的东西没有必要存在两个,有用的话,一个JSVM就OK了。不过我提倡代码开放,如果哪位网友有兴趣可以跟我说一声,我立刻双手奉上。
附:
1. JSVM在无忧脚本的原贴为 基本上实现 javascript 的 OOP (0423版)
2. 幻宇的星际在无忧脚本的原贴为 【原创】星际争霸js版进度:提供完整源码下载,大家都来down吧!!!
PS: 不是做广告,提供原贴是因为里边有许多非常好的讨论,可以学到许多东西。
二、JSVM是什么?
什么是JSVM?我想由万常华(wch3116)大哥自己来说比较准确,以下是在原贴里他的发言引用:
一直以来,js 没有统一的编写规范,导致许多优秀的代码不能很好的复用(function的复用性很差的)。就拿 51js 来说, 一直在讨论零散的技术,而不能借助众人的力量积累出一系列相对完整的“产品”,这都是因为没有“规范”,不成“体系”造成的。我希望能通过 JSVM 改变这种状态,就如斑竹所言,这只是一套方法(规范),而并完整的产品。众人拾柴火焰高,依照一个统一的规范,每个人根据自己的所长开发自己的类包,就能很好的流传开,被其他人使用。
(万常华的发言引用完)
很明显,JSVM要提供一个平台,或者是一个编码规范,通过类库可以减轻我们写脚本的工作量,同时我们也可以编写自己的类库,这一切在JSVM已经被实现了。
三、JSVM的架构
如果您真的决定继续把文章看下去,请先到JSVM无忧原贴下载最新的JSVM,在第一贴就能够找到,有两份代码,建议全部下载。
首先请解压缩第一份代码,也就是"jsvm & js 核心类库",可以看到有一个文件夹jsre,里边有两个文件夹classes、lib以及一个js文件jsvm.js。所有的类文件都应该放在classes下边,具体如何后边会讲。
这里的jsvm.js里边的代码就是JSVM的核心实现代码,我将会对里边做尽可能详尽的讲解与分析,如果不懂的话可以回贴提问,我会尽可能回复,如果有一些问题比较模糊,最好是直接到原贴里回贴发问,毕竟谁也没JSVM的作者更理解这份代码。
lib文件夹里有两个文件:JsLibTools.hta以及lib-inf.xml。前者是万常华自己提供的一个小工具,使用了HTA技术写的,主要用来把分散的js代码组织成一个xml文件,称它为lib。后者是lib的更新信息。
进入classes文件夹可以看到js文件夹以及class-inf.xml。js文件夹里存放的代码主要是优化JSVM以及为JSVM提供基础类的代码文件,按命名空间的形式存在,比如js.lang.Object这个类的代码就放在/jsre/classes/js/lang/Object.js里边。同时每个文件夹都有package.xml文件,这里边存放了该文件夹里的类信息。
另外万常华还提供了一个cn类库,即第二个代码下载,解压缩之后把cn文件夹放在classes里边。该类库与js类库不同的是它提供了许多实际应用中可以使用的代码,而前者提供了基础类。
JSVM系统变量:
$system_home: 系统目录,默认值为"/common/",这是以网站的绝对路径进行定义的,在使用JSVM之前必须进行修改。
$js_classpath: 类文件存放的根路径
$js_libpath: 类库文件存在放目录,这里的类库即前边所说的"lib"xml文件。
$js_runMode: 运行模式,有两个选项,一个是debug,一个是run。run模式是实际应用的运行模式,程序出了错不提醒访问者,另一个是debug模式,在写代码的时候有时候出了问题,设置为debug可以得到相关的出错信息。
PS: 从上边系统变量的定义可以看出一个特点:系统变量必须使用$开头。
四、JSVM的编码约定
编码约定万常万并没有给出一个比较详细的说法,不过我们可以从他在原贴的发言以及JSVM代码的组织中得出以下规范:
1. 系统变量必须使用$开头
2. 系统函数必须以_开头
3. 继承必须使用类的_extends方法而不允许直接使用prototype = new ClassName的方式
4. 所有的类都必须直接或者间接继承js.lang.Object
5. 包(package)的命名开头字母必须小写
6. 类(class)的命名开头字母必须大写
7. 在类的定义之中使用的临时变量必须以下划线_开头
8. 所有的类都必须严格遵守命名空间的约定(关于命名空间的组织可以查阅Java或者.NET)
9. 例外处理不要使用throw而是使用JSVM自定义的_throw
五、JSVM的例外处理
JavaScript本身就自带有一套例外处理,可以利用try-catch结构处理代码中可能出现的出错,但JSVM觉得这样还不够,因为这里的JavaScript是使用在Web页面中,如果没有使用try-catch的话还是同样会提供各种错误,JSVM是重写window.onerror把这种错误也拉进来一起处理,同时还定义了一个系统函数_throw,实现原理很简单,不需多讲。
具体的原型为window.onerror = function(msg, url, line)
msg为出错信息的描述,即Error对象的description属性
url为出错页面的url
line为出错的行数
在JSVM中,例外处理到处都会用到,这本来是很正常的事情,因为每一个程序员都应该处理所有可能会出现的错误。但因为种种原因,极少人在Web客户端的JavaScript中进行例外处理,大家都觉得没什么必要,从这一点也可以看出万常华编码的严谨。
六、JSVM的继承
在JavaScript中,继承是基于原型的,比如B类要继承A类可以这样子:
A.prototype = new B;
但是在JSVM中并没有如此简单,请看jsvm.js中的这段代码:
// * 定义实现 OOP 的相关方法
Function.prototype._extends = function(jsclass) {
try {
var _cn = (new RegExp("function[\\s]*([\\w|\\.]*)[\\s]*\\(")).exec(this.toString())[1]; // 得到完整类名
if (typeof(jsclass) == "string")
eval("jsclass = " + jsclass + ";");
if (typeof(jsclass) != "function")
_throw(0x000D, "JSVM/_extends:" + _cn + " 继承类错误{" + jsclass + "不是合法类}");
var _p = this.prototype = new jsclass(); // 原型继承
this._base = jsclass;
this._super = jsclass.prototype;
_p.className = _cn;
return _p; // 返回原型
} catch(ex) {
_throw(0x000E, "JSVM/_extends:" + _cn + " 继承类错误{" + ex.description + "}");
}
};
JSVM是直接给所有Function对象增加一个共用的方法_extends来实现继承,所有的类都可以通过 类名._extends("js.lang.Object")的形式来把某个类继承下来。
在继承函数里不仅使用原型继承,还同时做了许多工作,给做继承操作的子类增加了_base(父类对象)、_super(基类对象)、className(本类的类名),如果出现了任何错误还进行相关的例外处理。
待续。。。
回复 更多评论