JS技术

JavaScript支持继承_Javascript教程

字号+ 作者:H5之家 来源:H5之家 2015-09-25 18:03 我要评论( )

JavaScript支持继承,学习JavaScript支持继承,JavaScript支持继承,查看JavaScript支持继承,1. 支持多重继承例如子菜单类是这样写的 代码:import MenuItem;functio

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通过先编译再载入的方式,出现了很多很有意思的特性

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
网友点评