大家都知道jQuery是javascript面向对象开发思想成功实践者,在网站开发中经常用到jQuery库,它使js开发变得简洁快速的同时又对兼容性做了处理,使我们省事不少,同时也有不少基于jQuery开发的类库和组件应运而生。jQuery灵活的接口设计方便了自己扩展插件,今天就分析下jQuery的设计模式,分析下基础框架结构。

以最新版本的jQuery库(jquery-2.1.4)为例,下面是我对jQuery架构进行提取主要模块如下:

(function( global, factory ) {

    if ( typeof module === "object" && typeof module.exports === "object" ) {
        module.exports = global.document ?
            factory( global, true ) :
            function( w ) {
                if ( !w.document ) {
                    throw new Error( "jQuery requires a window with a document" );
                }
                return factory( w );
            };
    } else {
        factory( global );
    }

// Pass this if window is not defined yet
}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {

     //以函数表达式方法定义jQuery对象,返回jQuery.fn.init所返回的对象,因此我们可以直接调用 jQuery(selector, context) 而不需要使用 new 关键词
     var jQuery = function( selector, context ) {

          // 当new jQuery.fn.init后, jQuery.fn.init.prototype = jQuery.fn = jQuery.prototype
         // 相当于将所有jQuery.fn的方法都挂载到了执行 jQuery 函数返回的对象上
        return new jQuery.fn.init( selector, context );
     }
     //创建jQuery对象原型,为jQuery添加各种方法
     jQuery.fn = jQuery.prototype = {
         ……
     }

     // 创建jQuery.extend方法,实现jQuery对象的深/浅拷贝
     jQuery.extend = jQuery.fn.extend = function() {
         ……
     }

     //扩展jQuery对象上的静态方法,不少人称jQuery的工具方法
     jQuery.extend({
         ……
     })

     //扩展jQuery的实例方法,也称原型方法
     jQuery.fn.extend({
         ……
     })

     //扩展jQuery的实例方法
     var init = jQuery.fn.init = function( selector, context ) {

     }

     //给初始化原型赋值为jQuery对象的原型
    init.prototype = jQuery.fn;
    
     //为window全局对象暴露jQuery/$接口
    if ( typeof noGlobal === strundefined ) {  //var strundefined = typeof undefined
         window.jQuery = window.$ = jQuery;
    }

    return jQuery;

}));

相信有对Javascript面向对象开发思想经验的伙伴们看到我提炼出来的这段代码,应该会有理解,中间部分的代码功能模块我备注详情不再多说了。下以主要对开头的源码进行分析,我觉得这里设计的很巧妙很灵活。

对于jQuery初学者当你看源码时,从源码头开始可能会感到费解,特别是这行代码:

// Pass this if window is not defined yet
}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {  //不知道function( window, noGlobal )到哪里结束了

下面对jQuery源码头再次提取如下:

(function( global, factory ) {

    if ( typeof module === "object" && typeof module.exports === "object" ) {
        module.exports = global.document ?
            factory( global, true ) :
            function( w ) {
                if ( !w.document ) {
                    throw new Error( "jQuery requires a window with a document" );
                }
                return factory( w );
            };
    } else {
        factory( global );
    }

// Pass this if window is not defined yet
}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
    …… //这里是主函数体
})
);

是不是感觉清晰多了,下面对主架构函数再次简化成以下:

(function( global, factory ) {
    ……//兼容非window全局对象,如nodejs
}(param1,param2))

// @param1 就是typeof window !== "undefined" ? window : this    //传入全局对象,非window传入this,如nodejs this 指向global
// @param2 就是function( window, noGlobal ) { …… //这里是主函数体 }  //传入jQuery主函数体

这种形式的函数结构称为:立即调用函数表达式或者立即执行匿名函数。可见jQuery源码就是一个立即执行的匿名函数。下面我们再看下这个匿名函数有什么作用?

看了jQuery库的英文注释:

// For CommonJS and CommonJS-like environments where a proper `window`
// is present, execute the factory and get jQuery.
// For environments that do not have a `window` with a `document`
// (such as Node.js), expose a factory as module.exports.
// This accentuates the need for the creation of a real `window`.
// e.g. var jQuery = require("jquery")(window);
// See ticket #14549 for more info.

我们大概知道它是为了兼容nodejs、SeaJS等符合CommonJS规范或类CommonJS规范的js框架而做的处理。

再看下这行判断语句:

if ( typeof module === "object" && typeof module.exports === "object" )

学过nodejs的伙伴应该会知道module.export和export是nodejs中用来创建模块的方法,那么就好理解了,若条件成立则要执行下面语句来兼容nodejs,说白了就是利用形参factory做中间件,来把jQuery的各个功能模块用nodejs创建模块的方法创建成功;若条件不成功执行else部分说明没有用到像nodejs这种CommomJS规范的框架。好了,先写到这吧。

最近更新:2015-10-17
转载注明:http://www.ddbing.com/detail/51.html  [复制链接]
尊重知识|文明读者
boxUI on the road
最新评论