1. 支持多重继承
例如子菜单类是这样写的
代码:
import MenuItem;
function MenuSub extends Closable, Attachable{
var __items = [];
function MenuSub(){ addClass("menu_sub"); }
public function show(){ if(__items.length<1)return; open(); relocation(); }
public function hide(){ if(__items.length<1)return; close(); }
public function addItem(text, url){
var o = new MenuItem();
o.text(text);
o.appendTo(obj);
__items.push(o);
}
public function items(index){ return __items[index]; }
}
2. 支持头文件引用
例子见上面的代码
3. 允许构造函数,自动执行可能存在的initialize函数
还是上面的例子,在构造MenuSub类的实例的时候,会自动调用其 MenuSub 构造函数
4. 支持阻塞的包含
例如可以这样写代码:
代码: include ../js/somePack.js; useSomeFunctionInThatPack();
俺写的核心代码实现了JS的二次编译,只有9K大小哦~~哈哈
代码:
/*
* 核心 - 远程获取、全局执行、错误捕获、多线程、URL路径解析
* @author hutia
* @email hutia2@163.com
*
*/
/* Mini 远程获取 */
var _ = new function(){
var cache = {};
this.get = function(url, callback, obj){
if(cache[url])return callback.apply(obj, [cache[url]]);
var _ = (function(){
try{ return new XMLHttpRequest(); }catch(e){}
try{ return new ActiveXObject("Msxml2.XMLHTTP"); }catch(e){}
try{ return new ActiveXObject("Microsoft.XMLHTTP"); }catch(e){}
})();
_.open("GET", url, true);
_.onreadystatechange = function(){ if(_.readyState!=4)return; cache[url] = _.responseText; callback.apply(obj, [_.responseText, _]);}
_.send();
}
}
/* 全局执行 */
function eval_global(s){ try{ if(window.execScript)window.execScript(s); else window.eval(s); }catch(e){ traceError(e); } }
/* 错误捕获 */
var debug = true;
if(typeof debug == "undefined")window.onerror = function(e){ traceError(e); return true; }
function traceError(e){
var info = [];
if(debug){
if(typeof e == "object")for(var i in e)info.push(i+"\t: " + e[i]);
else info.push(e);
alert(info.join("\r\n"));
}
}
/* 多线程 - 挂起 */
function suspend(url, callback, obj){ _.get(url, callback || arguments.callee.caller, obj); }
/* URL路径解析 */
function URL(s){
var re = [], b = /^[\\\/]/.test(s)?"\/":"", e = /.+[\\\/]$/.test(s)?"\/":"", s = s.split(/[\\\/]/);
for(var i=0; i<s.length; i++){
if(s[i] == "..")re.pop();
else if((s[i] != "" || i == s.length-1 || i == 0) && s[i] != ".")re.push(s[i]);
}
return b + re.join("\/") + e;
}
/*===============================
* 核心 - 装载器
* @author hutia
* @email hutia2@163.com
*
===============================*/
//全局执行指定地址的脚本,执行完毕后调用 onfinish 函数(可选)
function include(url, onfinish){
if(typeof url == "string"){
load_js(url, function(s){
eval_global(s);
if(onfinish)onfinish();
});
}else if(typeof url == "function"){
try{ url(); }catch(e){ traceError(e); }
if(onfinish)onfinish();
}
}
//依次载入每个地址的脚本,编译并执行
function include_in_sequence(){
var method = arguments.callee, started = false;
if(!method.tasks)method.tasks = [];
if(method.tasks.length > 0)started = true;
for(var i=arguments.length-1; i>-1; i--)method.tasks.unshift(arguments[i]);
function run(){ if(method.tasks.length > 0)include(method.tasks.shift(), run); }
if(!started)run();
}
//载入指定url地址的脚本,编译后作为参数传递给 onfinish 函数
function load_js(url, onfinish){
_.get(url, function(s){
new Compiler(s, url, function(s){
onfinish(Compiler.seal(s));
});
});
}
/*===============================
* 核心 - 编译器
* @author hutia
* @email hutia2@163.com
*
===============================*/
//编译器类
function Compiler(source, baseURL, onfinish, extendsHash, obj){
//关键字匹配
var matcher = /\b(import)\s+([\w \t,.$]+)[;\r\n]|\b(extends)\s+([\w\s,.$]+)([^{]*)\{|\b(include)\s+([\w \t,.$]+)[;\r\n]/;
//缓存,输出,头文件,解析指针,基础URL,任务列表,继承链
var cache = source, result = [], imports = [], parse_point = 0, baseURL = URL(String(baseURL || "")), tasks = [], extendsHash;
//当前方法
var method = arguments.callee;
//全局头文件hash
if(!method.imported)method.imported = {};
//初始化继承链
if(!extendsHash)extendsHash = {};
//记录当前文件
extendsHash[baseURL] = true;
//计算基础URL
baseURL = baseURL.replace(/[\/\\][^\/\\]*$/, "");
if(baseURL)baseURL = baseURL + "\/";
//解析器
function parse(prefixData){
var j, s, asyn;
//处理前缀数据
if(prefixData)foundPrefixData(prefixData);
//处理任务
if(tasks.length > 0){
asyn = tasks.shift();
return suspend(asyn.url, asyn.callback, asyn);
}
//循环判断解析
while(matcher.test(cache)){
j = cache.search(matcher);
if(j != 0)foundCData(cache.substring(0, j)); //解析普通数据
s = cache.match(matcher);
asyn = foundCMD(s); //解析命令数据
cache = cache.substring(j + s[0].length, cache.length); //处理缓存
if(asyn)return suspend(asyn.url, asyn.callback, asyn);//挂起
}
if(cache != "")foundCData(cache); //解析末尾的普通数据
end(); //终止
}
function foundCMD(s){ //解析命令数据
var t, url;
if(s[1] == "import"){ //对于头文件
t = String(s[2]).replace(/[^\w,.$]+/g, "").split(","); //解析头文件列表
for(var i=t.length-1; i>-1; i--){
url = URL(baseURL + t[i] + ".js"); //计算URL
if(t[i] && !method.imported[url]){ //对于每个没有导入过的头文件(逆序)
method.imported[url] = true; //记录URL为已导入
//设置任务,自链表头部加入
tasks.unshift({"url": url, callback:function(s){
//编译获取的头文件
new Compiler(s, this.url, function(s){
//封装编译后的数据,记入头文件数据表(堆栈尾部入栈)
imports.push(Compiler.seal(s));
parse(); //继续恢复解析
});
}});
}
}
return tasks.shift(); //自链表头部取出任务
}else if(s[3] == "extends"){ //处理继承
result.push((/\([\s\S]*?\)/.test(s[5])?s[5]:"()") + "{"); //输出当前Class声明
t = String(s[4]).replace(/[^\w,.$]+/g, "").split(","); //解析继承列表
//对于每个父类(逆序),设置任务,自链表头部加入
for(var i=t.length-1; i>-1; i--){
url = URL(baseURL + t[i] + ".js"); //计算URL
if(t[i] && !extendsHash[url]){ //对于每个不在继承链上的文件
extendsHash[url] = true; //记录到继承链
tasks.unshift({"url": url, "name":t[i], callback:function(s){
//编译获取的父类
new Compiler(s, this.url, function(s){
result.push("\r\nfunction " + this.name + "(){}\r\n"); //输出默认构造函数
result.push(String(s.cdata).replace(/^[\s\S]*?\{/, "").replace(/\}[^\}]*?$/, "")); //输出父类函数体部分
result.push("\r\ntry{ "+this.name+".apply(this, arguments); }catch(e){ traceError(e); }\r\n"); //尝试执行构造函数
//记录父类的头文件信息,记入头文件数据表(堆栈尾部入栈)
imports = imports.concat(s.imports);
parse(); //继续恢复解析
}, extendsHash, this);
}});
}
}
return tasks.shift(); //自链表头部取出任务
}else if(s[6] == "include"){ //处理包含
t = String(s[7]).replace(/[^\w,.$]+/g, "").split(","); //解析包含列表
//对于每个包含文件(逆序),设置任务,自链表头部加入
for(var i=t.length-1; i>-1; i--){
url = URL(baseURL + t[i]); //计算URL
if(t[i])tasks.unshift({"url": url, callback:function(s){
//编译获取的包含文件
new Compiler(s, this.url, function(s){
result.push(String(s.cdata)); //输出文件体
imports = imports.concat(s.imports); //记录头信息
parse(); //继续恢复解析
});
}});
}
return tasks.shift(); //自链表头部取出任务
}
}
function foundCData(s){ result.push(s); } //解析普通数据:直接输出
function foundPrefixData(s){ cache = s + "\r\n" + cache; } //解析前缀数据:加载到缓存头部
function end(){ //终止
var re = {}; //用于返回的编译结果对象
//编译后的数据体,处理其中的public声明
re.cdata = result.join("").replace(/\bpublic(\s+function)?\s+([\w$]+)/g, function(s0, s1, s2){
return "this." + s2 + " = " + s2 + "; function " + s2;
});
//编译后的头信息
re.imports = [].concat(imports);
onfinish.apply(obj, [re]); //回调解析终了函数
}
parse(); //开始解析
}
//编译器类静态方法:封装
//用于封装头部文件和函数体
Compiler.seal = function(s){
//数据体,解析中间容器,类头部正则,输出
var c = s.cdata, mc, i, reg = /^[^{]*function\s+([\w$]+)\s*(\([^\)]*\))\s*\{/, result = [].concat(s.imports);
if(reg.test(c)){ //发现类头部声明
mc = c.match(reg); //获取解析结果
i = c.lastIndexOf("}"); //获取类结尾位置
result.push(mc[0]); //输出类声明
result.push("function " + mc[1] + mc[2] + "{}"); //输出默认构造函数
result.push(c.substring(mc[0].length, i)); //输出类函数体
result.push("try{" + mc[1] + ".apply(this, arguments);}catch(e){ traceError(e); }"); //试图执行构造函数
result.push("try{ _initialize(); }catch(e){ if(typeof _initialize != \"undefined\")traceError(e); }"); //试图执行初始化函数
result.push(c.substring(i)); //输出类结尾内容
}else{ //解析失败,直接输出内容
result.push(c);
}
return result.join("\r\n");
}
因为JS通过先编译再载入的方式,出现了很多很有意思的特性