JQuery是当前最流行的JavaScript库,出于好奇,我研究了jQuery的源代码,我使用的版本是1.3.2。在接下来的几篇文章里,我将对jQuery实现作详尽的详解。
使用jQuery的第一步就是构建jQuery对象,所以让我们先来看jQuery对象的构造函数。
构造函数在第24行, 它被同时赋给window.jQuery和window.$,因此jQuery和$两者等价,构造函数直接调用jQuery.fn.init方法。 init方法根据参数类型接受几种不同形式的方法调用,在第41行根据selector是否有nodeType属性来判断selector是否是 DOMElement,如果是则将该JQuery对象设置为只包含一个元素,也就是selector,另外将上下文对象(context)也设置为 selector。 在该对象48行,如果selector是一个字符串,则会根据selector是HTML字符串(如"<p>some content</p>")还是CSS选择器(如"div#myClass")来执行不同的逻辑,这在后面会详述。在82行,如果 selector是一个函数,调用jQuery(document).ready(selector),表示在document的DOM树加载完成之后执 行该函数。在86到88行作用是当selector也是一个JQuery对象时,将该JQuery对象的selector和context属性也复制过 来。在91行处,selector一般是一个包含多个DOMElement的数组,如果不是则构造一个大小为1的数组,其唯一元素为该 selector(makeArray实现),然后将selector数组的内容复制到jQuery对象中,这样jQuery表现得像数组,它有 length属性,可以通过[0]...[length-1]来访问各个元素的内容,这个功能由setArray完成。setArray的实现很巧妙,它 调用Array.prototype.push方法:
jQuery对象并不复杂,它包含三个属性:包含的DomElement数组,selector属性和context属性。将DomElement数组称 为一个属性并不恰当,因为jQuery对象实际上包含length属性,以及名称0, 1, ..., length-1的属性。selector属性是一个CSS选择器,它是一个字符串,只有当调用jQuery构造函数时,selector参数为一个 CSS选择器时,它的值才会被设置,否则就是空字符串("")。context属性则为jQuery对象的上下文对象,我的理解也可以称做“根对象”,当 jQuery根据CSS选择器来选择匹配DOMElement时,只会搜索以context元素为根的DOM树。当构造HTML字符串构造jQuery对 象时没有context忏悔。复杂的地方不在jQuery对象本身,而在于selector为字符串是它的构造过程,尤其是当selector为CSS选 择器的时候。现在来看看上面被折叠的代码(48行到82行之间的代码):
在53行if判断:selector是HTML字符串(match[1]不为空)或者ID(match[3]不为空)时,或者没有指定 context对象。接下来在56行,如果selector是HTML字符串,则调用clean方法将HTML字符串转化成DOMElement。 clean方法实现比较复杂(这里就不列出源代码了),主要是因为要处理各种浏览器的兼容问题,但总体步骤也简单。首先它判断HTML是否为简单的单个元 素(如<p>, <div/>等,有没有/并不重要),则直接调用document.createElement来创建该元素。否则,则调用 document.createElement("DIV")来创建一个div元素,然后设置它的innerHTML为该HTML字符串,最后调用div 元素的childNodes来得到DomElement数组。第60行处理selector为ID选择器的情形(#someID),主要是为了优化,因为这种情形出现得最多,61行到66的复杂之处是要处理IE的兼容问题,69到72行创建jQuery对象,并设置context,seletor属性。第 77行处理selector为CSS选择器的情形,调用jQuery的find的方法,这是jQuery最复杂的部分,留到下次再说。