2011年3月12日星期六

jQuery源码学习

jQuery是一个非常优秀的javascript库,前一段时间YUI和jQuery有过一场争论,其实我觉得它们都还不错,只是适用的地方不同。对于小型的简单的应用,jQuery的开发效率是非常高的。我们废话少说,进入正题吧。

对于大多数人来说它就像一个magic black box,但jQuery是如何工作的,可能研究的人就不多了。本文稍微谈一下,jQuery源码,以及它的工作原理。

jQuery的源码host在github.com上,现在正在处于1.5向1.6的开发阶段。将master branch拉下来make一下,就可以在dist目录下看到jquery.js了。或者如果你更愿意看分模块的code,就直接到src下看。

Overview
打开jquery.js,它的基本结构是这样的:
// This is an self-executing anonymous function
(function(window, undefined) {
    var jQuery = (function() {
        var jQuery = function(selector, context) {
            return new jQuery.fn.init(selector, context, rootjQuery);
        },
            rootjQuery;

        jQuery.fn = jQuery.prototype = {
            constructor: jQuery,
            init: function(selector, context, rootJQuery) {
                // ...
                return this;
            }
            // ...
        };

        jQuery.fn.init.prototype = jQuery.fn;

        return jQuery;
    })();
    
    // ...

    window.jQuery = window.$ = jQuery;

})(window);

// alert($());

Self-executing anonymous function
最外层是一个自执行的匿名函数(self-executing anonymous function)。它有两个作用:
  1. 作为一个匿名的namespace。在函数内部的变量不再是全局变量,不会影响到其他库和用户代码,也不会受它们的影响。
  2. 防止恶意程序改写undefined(javascript允许重新定义这个关键字,evil feature),一个简单的例子如下。jQuery定义了一个两个参数的函数,调用的时候只传一个。保证了函数中的undefined一定是“真的”undefined。



函数内部第3行定义了一个内部对象jQuery,第25行将这个对象export到global space,赋值给window.$和window.jQuery。然后$("#id")就可以work了。

第3-21行又定义了一个自执行的匿名函数,作用一样,是一个namespace,在jQuery不同模块之间做隔离。第4行再次定义了一个jQuery,在第20行返回了这个jQuery。这个jQuery就是最终用户得到的对象(函数也可以认为是对象)。



What jQuery is?
这个jQuery是个什么呢?

它是一个function(同时又是一个constructor function和object),所以以下三种用法都是可以的。



可以看到作为function和constructor function它的意义是一样的,它会返回一个jQuery.fn.init的对象。
jQuery.fn.init在第12行定义,它做的事情就是parse输入的selector和context,返回jQuery对象。这个名字比较绕,其实可以把jQuery.fn.init看作一个整体就好理解多了。第9-18行其实可以理解成下面一行代码。不管你的object是new $("#id")还是$("#id"),对它们调用的方法会落到这个prototype中。

(jQuery.fn.init).prototype = jQuery.fn = jQuery.prototype = { 
    //... 
}; 

Extending jQuery
因此如果要在上述object上扩展一个方法,很简单

// The following notations are OK as well:
// $.fn.init.prototype.new_func
// $.prototype.new_func
$.fn.new_func = function() {
    // ...
}

当然jQuery提供了专门的方法($.fn.extend)做这件事情。

另外我们还看到$.browser这样的方法。要扩展这样的方法同样很简单

$.new_func() = function() {
    // ...
}

同样,jQuery提供了专门的方法($.extend)做这件事情。

这里大家也发现了,jQuery有两类方法,$("").xxx和$.xxx。在jQuery的官方文档上它也是加以区分的,
Resources
一些比较好的资源:

    没有评论: