第二章 : 种子模块

种子模块也叫核心模块,是框架中最早执行的部分。即使像jQuery那样的单文件函数库,它的内部也分不少模块,必然有一些模块执行时在最前面当即执行,有一些模块只有用到才执行。有的模块无关紧要,存在感比较弱,只有在特定的浏览器下才运行。javascript

种子模块就是其中的先锋,它里边的方法不必定要求个个功能齐全,设计优良,但必定要极具扩展性,经常使用,稳定css

扩展性是指经过他们能给将其它模块包含进来;经常使用是指绝大多数的模块都能用到它们,防止作重复工做。稳定是指在版本迭代时不轻易被新方法替代。html

参照许多框架和库的实现,咱们认为种子模块包含以下功能对象扩展数组化类型断定简单的绑定与卸载无冲突处理模块的加载domReady.本章学习的内容以mass Framework种子模块为范本。java

https://github.com/RubyLouvre/mass-Frameworknode

1.命名空间git

种子模块做为一个框架最开始的部分,负责辅建全局的基础设施外。jQuery就有一个很好的开头,使用IIFE(当即调用函数表达式).github

LIFE是现代javascript框架里最主要的基础设施,它就像细胞同样包裹自身,防止变量污染。就像一个立足点,这个就是命名空间,如prototype.js,mootools,它们让你感觉不到框架的存在,它的意义深入到javascript、DOM、BOM等整个执行环境的每一个角落,对原生的对象原型就行扩展。因为道格拉斯(JSON做者)的极力反对,新的框架都在命名空间上构建了。chrome

咱们看怎么在javascript上模拟命名空间。javascript一切基于对象,但只有符合类型的对象才符合要求,好比function 、RegExp、Object,不过最经常使用的是object和function。咱们往一个对象上添加一个属性,而这个属性又是一个对象,这个对象咱们又能够为它添加一个对象,经过这种方法,咱们就能够有条不紊的构建咱们的框架。用户想调用某个方法,就以xxx.yyy.zzz()的形式调用windows

    if( typeof(Ten) === "undefined" ){
        Ten = {};
        Ten.Function = {  /**/ }
        Ten.Array = {  /**/ }
        Ten.Class = {  /**/ }
        Ten.JSONP = new Ten.Class(/**/ )
        Ten.XHR = new Ten.Class(/**/ )
    }

纵观各大类库的实现,一开始基本都是定义一个全局变量做为命名空间,而后对它进行扩展,如Base2的Base,Ext的Ext,jQuery的jQuery,YUI的YUI,dojo的dojo,MochiKit的mochKit。从全局变量的污染程度来看,分为两类:api

prototype.js和mootools与Base2归为一类,Prototype的哲学是对javascript的原生对象进行扩展。早些年,prototype差点称为事实的标准。所以没有考虑到与其它库共存的问题。基本Prototype,也发展出诸如script.aculo.us,rico,Plotr,protoChart,Script2等很是优秀的类库以一大类收费插件。并且,有些渊源的插件几乎都与Prototype有关,好比lightBox。mootools是prototype.js的升级版,更加OO,全面复制其API。Base2则是想修复IE的bug,让IE拥有标准浏览器的API,所以也把全部原生的对象污染一遍

第二类是jQuery,YUI,EXT这些框架YUI和Ext就是对象嵌套对象的方式构建的。jQuery则另辟蹊径,它是以选择器为导向的,所以它的命名空间是一个函数,方便用户将css表达器的字符串传进来。而后经过选择器进行查找,最后返回一个jQuery对象实例。

jQuery最开始也像Prototype使用$做为它的命名空间,所以,它实现了不少库的共存机制,在$和jQuery中任意切换,jQuery的多库共存原理很简单,所以后来也成为许多小库的标配。首先,把命名空间保存到一个临时变量中(注意,这时候这个对象并非本身框架的东西,多是prototype.js或者其余的),而后再使用个noConflict放回去。

    //jQuery1.2
    var _jQuery = window.jQury , _$ = window.$; //把可能存在同名变量先保存起来
    jQury.extend({
        noConflict : function(deep) {
            window.$ = _$; //这时再放回去
            if (deep)  //补充 if ( deep && window.jQuery === jQuery )
                window.jQury = _jQuery;
            return jQury;
        }
    })

参考:http://zhidao.baidu.com/question/1239712776390687219.html

但jQuery的noConflict只是对单文件的类库框架有用,像Ext就不能复制了。所以把命名空间更名后,将Ext置为null,而后经过动态加载的方法引入新的javascript文件中,该文件会以Ext调用,会致使报错

2.对象扩展

咱们须要一种机制,将新功能添加到咱们的命名空间上来。这方法在javascript一般称做extend或mixin。javascript对象在属性描述符(Property Descriptor)没有诞生以前,是能够随意添加、更改、删除其成员的,所以,扩展一个对象很是便捷。一个简单的扩展方法实现是这样的。

    function extend (destination,source){
        for (var property in source)
            destination[property] = source[property];
        return destination;
    }

不过,旧版本IE在这里有个问题,它认为像Object的原型方法就是不该该被遍历出来,所以for in循环是没法遍历valueOf、toString的属性名。这致使,模拟Object.keys方法是现实时也遇到了这个问题。

    Object.keys = Object.keys || function(obj){
        var a = [];
        for(a[a.length] in obj);
        return a;
    }

在不一样的框架,这个方法还有不一样的实现,如Ext分别为apply与applyIf两个方法,前者会覆盖目标对象的同名属性,然后者不会。dojo容许多个对象合并在一块儿。jQuery还支持深拷贝。下面是mass Farmework的mix方法。支持多对象合并与选择是否覆写。

    function mix(target,source){ //若是最后参数是布尔,断定是否覆盖同名属性
        var args = [].slice.call(arguments), i = 1, key,
            ride = typeof args[args.length - 1] == "boolean" ? args.pop() : true;
        if (args.length === 1){ //处理$.mix(hash)的情形
            target = !this.window ? this : {};
            i = 0;
        }    
        while ((source = args[i++])) {
            for (key in source){ //容许对象糅杂,用户保证都是对象
                if (ride || !(key in target)) {
                    target[key] = source[key];
                }
            }
        }
        return target;
    }

3.数组化

浏览器下存在不少类数组对象,如function内的arguments,经过document.forms、form.elements,document.links、select.options、document.getElementsByName,document.getElementsByTagName、childNodes、children等方式获取的节点的结合(HTMLCollection 、NodeList)或按照某些特殊的写法自定义对象。

类数组对象是一个很好的存储结构。不过功能太弱了,为了能使用纯数组的那些便捷的方法,咱们会在处理它们前都会作一下转换。

一般来讲,使用[].slice.call就能转换了 ,不过功能不够用,但在旧版本的HTMLCollection、NodeList不是Object的子类,采用如上的方法会致使IE执行异常。咱们看一下

jQuery:makeArray

    var makeArray = function(array) {
        var ret = [] ;
        if(array != null){
            var i = array.length;
            if(i == null || typeof array === "string" || jQuery.isFunction(array) || array.setInterval)
                ret[0] = array;
            else
                while (i)
                    ret(--i) = array[i];
        }
        return ret;
    }

mass的实现,一开始就进行区分,直接[].slice.call,IE的话本身动手实现一个slice方法

    $.slice = window.dispatchEvent ? function(nodes,start,end){
        return [].slice.call(nodes,start,end);
    } : function (nodes,start,end){
        var ret = [],
              n = nodes.length;
        if (end === void 0 || typeof end === "number" && isFinite(end)){
            start  = parseInt (start,0) || 0;
            end = end == void 0 ? n:parseInt (end,10);
            if(start < 0){
                start += n;
            }
            if (end > n) {
                end =n
            };
            if (end < 0) {
                end += n
            };
            for (var i = start; i < end; ++i){
                ret[i-start] = nodes[i];
            }
        }
        return ret;
    }

4.类型的断定

javascript存在两套类型系统,一套是基本的数据类型,另外一套是对象类型系统。基本数据类型包括6中 。分别是undefined、string、null、boolean、function、object。基本数据类型是经过typeof来检测的。对象类型系统是以基础类型系统为基础的,经过instanceof来检测的。然而,javascript自带的这两套识别机制很是不靠谱,因而就催生了isXXX系列。就拿typeof来讲,它只能粗略识别出string、number、boolearn、function、undefined、object这6种数据类型,没法识别null,RegExpArgument等细分的对象类型。

    typeof null // => "object"
    typeof document.childNodes //=> safari: "function"
    typeof document.creatElement('embed') //=> ff3-10 "function"
    typeof document.creatElement('object') //=> ff3-10 "function"
    typeof document.creatElement('object') //=> ff3-10 "function"
    typeof /\d/i //在实现了ecma262v4的浏览器返回"function"
    typeof window.alert //ie678 "object"
    var iframe = document.creatElement("iframe")
    document.body.appendChild(iframe)
    xArray = window.frames[window.frames.length - 1].Array;
    var arr = new xArray(1,2,3) //=>[1,2,3]
    arr instanceof Array ;// false
    isNaN("aaa") //=> true

另外,之前人们老是以document.all来判断是否为ie,这实际上是很危险的,由于,用document.all来取得页面中全部的元素是不错的注意,这个方法FF,chrome打算使用好久了,不过人们都这样判断,就是在chrome下有这样的闹剧。

    typeof document.all //undefined
    document.all //HTMLAllCollection [728] (728为元素总数)

在断定undefined、null、string、number、boolean、function这六个还算简单,前面两个能够分别与void(0)、null比较,后面4个的typeof也能够知足90%的情形。这样说是由于string、number、boolean能够包装成伪对象。

    typeof new Boolean(1); //=>"object"
    typeof new Number(1); //=>"object"
    typeof new String("aa"); //=> "object"

这些还不是最难的,难点在于RegExp与Array.断定RegExp的状况不多。Array则不同。有关isArray的实现不下二十种。都是由于鸭式辨型被打破了。直到prototype.js把Object.prototype.toString发掘出来。此方法是直接输出内部的[[Class]],绝对精准。有了它,95%的陷阱被跳过了。

    function isArray(arr){
        return arr instanceof Array;
    }

    function isArray(arr){
        return !!arr && arr.constructor === Array;
    }

    function isArray(arr) { //prototype.js 1.6
        return arr != null && typeof arr === "object" && 'splice' in arr && 'join' in arr;
    }

    function isArray(arr){// Douglas Crockford(JSON做者,反对原型污染)
        return typeof arr.sort == "function"
    }

    function isArray(array){ //kriszyp
        var result = false;
        try{
            new array.constructor (Math.pow(2,32))
        } catch (e){
            result = /Array/.test(e.message)
        }
        return result;
    };

    function isArray(o){//kangax
        try{
            Array.prototype.toString.call(o);
            return true;
        } catch (e) {
        }
        return false;
    }

    function isArray(o){ //kangax
        if(o && typeof o == 'object' && typeof o.length == 'number' && isFinite(o.length))
        {
            var _origLength = o.length;
            o[o.length] = '__test__';
            var _newLength = o.length;
            o.length = _origLength;
            return _newLength == _origLength + 1;
        }
        return false
    }

至于null 、 undefined 、NaN直接这样写

    function isNaN(obj) {
        return obj !== obj
    }

    function isNull(obj) {
        return obj === null;
    }

    function isUndefined(obj){
        return obj === void 0;
    }

最后要断定的是对象是window,因为ECMA是不规范的Host对象,window对象属于host.因此也就没有被约定。就算Object.prototype.toString也对它没办法

    [object Object] IE6 
    [object Object] IE7 
    [object Object] IE8
    [object Window] IE9
    [object Window] ff3.6
    [object Window] opera10
    [object DOMWindow] safari 4.04
    [object global] chrome5.0

不过根据window.window和window.setInterval去断定更加不靠谱,用一个技巧就能够完美识别ie6 ie7 ie8的window对象,其它还用toString,这个神奇的hack就是,window与document互相比较,若是顺序不同,结果也是不同的

剩下的就是一些经典方法:

在prototype.js中,拥有isElement,isArray,isHash,isFunctoion,isString,isNumber,isDate,isUndefined

mootools有一个typeOf断定基本类型,instanceOf断定自定义“类”

RightJS 有isFunction , isHash , isString , isNumber , isArray ,isElement, isNode.

Ext有比较全面的判断,isEmpty,isArray,isDate,isObject,isSimpleObject,isPrimitive,isFunction,isNumber,isMumeric,isString,isBoolean,isElement,isTextNode,isDefined,isIterable,应有尽有。最后,还有typeOf判断基本类型。

Underscore.js有isElement,isEmpty,isArray,isArgument,isObject,isFunction,isString,isNumber,isFinite,isNaN,isBoolean,isDate,isRegExp,isNull,isUndefined.

jQuery就不与其它框架同样了,在jQuery1.4中只有isFunction,isArray,isPlainObject,isEmptyObject。isFunction,isArray用户确定用的较多,isPlainObject是用来判断是不是纯净的js对象。既不是DOM,BOM对象,也不是自定义的“类”的实例对象,制造它的目的最初是为了深拷贝,避开像window那样本身引用本身的对象。isEmptyObject是用于数据缓存的系统,当此对象为空时,就能够删除它。

    //jQuery2.0纯净数组的断定思路
    jQuery.isPlainObject = function(obj){
        //首先排除基础类型不为Object的类型,而后是DOM节点与window对象
        if(jQuery.type(obj) !== "object" || object.nodeType || jQuery.isWindow(obj)){
            return false;
        }

        //而后回溯它的最近的原型对象是否有isPrototypeOf.
        //旧版本的IE一些原生的对象没有暴露constructor、prototype。所以在这里过滤掉
        try{
            if (obj.constructor && !hasOwn.call(obj.constructor.prototype,"isPrototypeOf")){
                return false;
            }
        } case(e) {
            return false;
        }
        return true;
    }

 

avalon.mobile中有一个更精简的版本,只支持最新的浏览器,能够大胆的使用ecma262v5新API

    avalon.isPlainObject = function(obj){
        return obj && typeof obj === "object" && Object.getPrototypeOf(obj) === Object.prototype
    }

isArrayLike也是一个经常使用的方法,可是断定一个类数组太难了,惟一的识别方法就是判断有一个大于0或等于0的length属性,此外,还有一些共识,如window与函数和元素节点,如(form元素),不算类数组,虽然它们都知足前面的条件。所以,至今jQuery都没有把它暴露出来。

    //jQuery2.0
    function isArrayLike(obj){
        var length = obj.length , type = jQuery.type(obj);
        if (jQuery.isWindow(obj)){
            return false;
        }
        if (obj.nodeType === 1 && length){
            return true
        }
        return type === "array" || type !== "function" && (length === 0 || typeof length === "number" && length > 0 && (length -1) in obj);
    }

    // avalonjs
    function isArrayLike (obj) {
        if (obj && typeof obj === "object"){
            var n = obj.length
            if (+n === n && !( n % 1) && n >= 0){//检测length是否为非负整数
               try{
                   if ({}.prototypeIsEnumerable.call(obj,'length') === false){
                    return Array.isArray(obj) || /^\s?function/.test(obj.item || obj.callee)
                 }
                return true;
              } catch (e) { //IE的NodeList直接报错
                return true;
              }
            }
        }
    return false
    }

 

在Prototype.js1.3版本中的研究成果(Object.prototype.toString.call)就应用于jQuery,在jQuery1.2中,判断一个变量是否为函数很是复杂。

    isFunction : function(fn){
        return !!fn && typeof fn != "string" && !fn.nodeName && fn.constructor != Array && /^[\s[]?function/.test(fn + ""); 
    }

jQuery1.43中引入isWindow来处理makeArray中对window的断定,引入isNaN用于确保样式赋值的安全同时引入type代替typeof关键字,用于获取基本数据的基本类型。

    class2type = {};
    jQuery.each("Boolean Number String Function Array Date RegExpObject".split("  "),function( i , name ){
        class2type[ "[object " + name + "]" ] = name.toLowerCase();
    });

    jQuery.type = function(obj){
        return obj == null ? String(obj) : class2type[toString.call(obj)] || "object";
    }

jQuery1.7中添加isNumeric代替isNaN。这是个不一样于其它框架的isNumber,它能够是个字符串,只要外观上像数字就能够了。但jQuery1.7还作了一个违背以前提到稳定性的事情。冒然去掉jQuery.isNaN,所以,基于旧版jQuery的有大批插件失效。

    //jQuery.1.43-1.64
    jQuery.isNaN = function ( obj ) {
        return obj == null || !rdigit.test( obj ) || isNaN( obj );
    }

    //jQuery1.7就是isNaN的去反版
    jQuery.isNumeric =  function ( obj ) {
        return obj != null && rdigit.test( obj ) && !isNaN( obj );
    }

    //jQuery.1.71 - 1.72
    jQuery.isNumeric =  function ( obj ) {
        return !isNaN( parseFloat(obj) ) && isFinite( obj );
    }

    //jQuery2.1
    jQuery.isMumeric  = function( obj ) {
        return obj - parseFloat(obj) >= 0;
    }

massFarmeWork的思路与jQuery一致,尽可能减小isXXX系列的代码,把is Window,isNaN,nodeName等方法作了整合。代码较长,既能够获取类型,也能够传入第二参数进行类型比较

    var class2type = {
        "[objectHTMLDocument]" : "Document",
        "[objectHTMLCollection]" : "NodeList",
        "[objectStaticNodeList]" :  "NodeList",
        "[objectIXMLDOMNodeList]" : "NodeList",
        "[objectDOMWindow]" : "window",
        "[object global]" : "window",
        "Null" : "Null",
        "undefined" : "undefined"
    },
    toString = class2type.toString;
    "Boolean,Number,String,Function,Array,Date,RegExp,Window,Document,Arguments,NodeList".replace($.rword,function( name ) {
        class2type[ "[object" + name + "]" ] = name;
    });

    //class2type这个映射几乎把经常使用的断定对象一网打尽
    mass.type = function( obj , str ){
        var result = class2type[ (obj == null || obj !== obj) ? obj : toString.call(obj) ] || obj.nodeName || "#";
        if(result.charAt(0) === "#") { //兼容旧版浏览器的个别状况,如window.opera
            //利用IE678 window === document为true,document === window为false
            if( obj == obj.document && obj.document != obj ) {
                result = "window"; //返回构造器名称
            } else if ( obj.nodeType === 9 ) {
                result = "Document";
            } else if ( obj.callee) {
                result = "Arguments";
            } else if ( isFinite(obj.length) && obj.item ) {
                result = "NodeList" //处理节点集合
            } else {
                result = toString.call(obj).slice(8,-1);
            }
        }
        if(str){
            result str === result;
        }
        return result;
    }

而后type方法就十分轻松了,用toSring.call(obj)得出值的左键,直接从映射中取得。IE678,咱们才费一些周折处理window,document,argument,nodeList等对象。

百度的七巧板基于实用主义,断定也十分严谨。与EXT同样,能想到的写上,而且断定十分严谨。

目前版本2.0.2.5 http://tangram.baidu.com/api#baidu.type()

    baidu.isDate = function( unknow ) {
    return baidu.type(unknow) == "date" && unknow.toString() != 'Invalid Date' && !isNaN(unknow);
    };
    baidu.isNumber = function( unknow ) {
    return baidu.type(unknow) == "number" && isFinite( unknow );
    };

 5.主流框架的引入机制-domReady

domReady实际上是一种名为"DOMContentLoaded"事件的别称,不过因为框架的须要,它与真正的DOMContentLoaded有一点区别,在不少新手和旧的书中,不少人将其写在window.onload回调中,防止dom树尚未建完就开始对节点操做。而对于框架来讲,越早越介入dom就越好,如要进行特征侦测之类的。domready还能够知足用户提早绑定事件需求,由于有时页面图片过多等,window.onload事件迟迟不能触发,这时用户操做都没有效果,所以,主流的框架都引入了domReady机制,而且费了很大周折才兼容全部浏览器。具体的策略以下

  • 对于支持DOMContentLoaded事件使用DOMcontentLoaded事件
  • 旧版本IE使用Diego perini发现的著名Hack
    //by Diego Perini 2007.10.5
     function IEContentLoaded (w, fn) {
     var d = w.document, done = false,
     // 只执行一次用户的回调函数init()
     init = function () {
        if (!done) {
            done = true;
            fn();
        }
     };
    (function () {
        try {
            // DOM树未建立完以前调用doScroll会抛出错误
            d.documentElement.doScroll('left');
        } catch (e) {
            //延迟再试一次~
            setTimeout(arguments.callee, 50);
            return;
        }
        // 没有错误就表示DOM树建立完毕,而后立马执行用户回调
        init();
                 })();
    //监听document的加载状态
    d.onreadystatechange = function() {
        // 若是用户是在domReady以后绑定的函数,就立马执行
        if (d.readyState == 'complete') {
            d.onreadystatechange = null;
            init();
        }
             };
    }

关于加载思路:http://www.cnblogs.com/horve/p/4092064.html

司徒正美《javascript的事件加载》:http://www.cnblogs.com/rubylouvre/archive/2009/08/26/1554204.html  


此外,IE还能够经过script defer hack进行断定

     document.write("<script id=__ie_onload defer src=//0 mce_src=http://0></scr"+"ipt>"); 
        script = document.getElementById("__ie_onload"); 
        script.onreadystatechange = function() { //IE即便是死链也能触发事件 
                    if (this.readyState == "complete") 
        init(); // 指定了defer的script在dom树建完才触发
    }; 

不过还有个问题,若是咱们的种子模块是动态加载的,在它插入dom树时,DOM树是否已经建完呢?这该怎么触发ready回调?jQuery的方案是,连onload也监听了 ,但若是连onload也没遇上,就断定document.readyState等于complete。(完美)惋惜ff3.6以前没有这属性,看mass的方案

    var readyList = [];
    mess.ready = function( fn ) {
        if ( readyList ) {
            fn.push( fn );
        } else {
            fn();
        }
    }
    var readyFn ,ready = W3C ? "DOMContentLoaded" : "readyStatechange";
    function fireReady() {
        for (var i = 0 , fn; fn = readyList[i++]) {
            fn();
        }
        readyList = null;
        fireReady = $.noop; //惰性函数,防止IE9调用_checkDeps
    }
    function doScrollCheck() {
        try { //IE下经过doScrollCheck检测DOM树是否建设完
            html.doScroll("left");
            fireReady();
        } catch (e){
            setTimeout(doScrollCheck);
        }
    }

    //FF3.6前,没有readyState属性
    //http://www.cnblogs.com/rubylouvre/archive/2012/12/18/2822912.html
    if (!document.readyState){
        var readyState = document.readyState  =  document.body ? "complete" : "loading";
        if (document.readyState === "complete") {
            fireReady(); //若是在domReay以外加载
        } else {
            $.bind(document,ready,readyFn = function(){
                if(W3C || document.readyState === "complete") {
                    fireReady();
                    if(readyState){ //IE下不能该项document.readyState
                        document.readyState = "complete";
                    }
                }
            });
            if (html.doScroll){
                try {//若是跨域就报错,证实有两个窗口
                    if (self.eval === parent.eval) {
                        doScrollCheck();
                    }
                } catch (e) {
                    doScrollCheck();
                }
            }
        }

    }

6.无冲突处理

无冲突处理也叫多库共存,$是这个重要的函数名,以致于你们都爱拿它来作本身的命名空间,当jQuery开始发展时,Prototype是主流,jQuery发明了noConflict函数

    var window = this,
    undefined,
    _jQuery = window.jQuery,
    _$ = window.$,
    //将window存入闭包中的同名变量,方便内部函数调用windows不用太麻烦查找它。
    //_jQuery与_$用于之后重写
    jQuery = window.jQuery = window.$ = function(selector, context){
        //用于返回一个jQuery对象
        return new jQuery.fn.init(selector,context);
    }

    jQuery.extend({
        noConflict : function(deep) {
            //引入jQuery类库后,闭包外边的window.$与window.jQuery都储存着一个函数
            //它是用来生成jQuery对象或在domReady后执行里面的函数
            //回顾最上面的代码,在尚未把function赋值给它们时,_jQuery和_$已经被赋值了,所以,它们两的值必然是undefined
            //所以,这种放弃控制权的技术很简单,就是用undefined把window.$里边jQuery函数清除掉。
            //这时,prototype或mootools的$就被拿走了
            window.$ = _$; //至关于window.$ = undefined,若是你有一个叫jQuery的库,也能大方的过渡出去。
            //这时,须要给noConflict添加一个布尔值,true
        
        if (deep)
            //但咱们必须使用一个东西接纳jQuery与jQuey的入口函数
            //闭包里边的东西除非被window等宿主引用,不然是不可见的
            //所以,咱们把闭包里的jQuery return出去,外面用一个变量接纳就能够
            window.jQuery = _jQuery; //至关window.jQuery = undefined
        return jQuery;
        }
    })

使用时,先引入别人的库,而后引入jQuery,使用调用$.noConflict()进行更名,这样就不影响别人的$运行了。

mass的操做方式是在script标签上定义一个nick属性,那么释放出来的命名空间就是你的那个属性值。里面实现了相似jQuery的机制。

<script nike="aaa" src="mass.js"></script>
<script>
    aaa.log("xxxxxx")
</script>

本章完结

上一章:第一章 : javaScript框架分类及主要功能     下一章:第三章 :模块加载系统

相关文章
相关标签/搜索