Jquery core解析
jquery的一般使用方式
jquery最常见的用法形如:
$(str).func1();
str可以是html或者一个选择器,$是个函数,可以把str转换成一个jquery对象。
一个jquery对象可以认为是一组dom对象的包装,jquery对象支持多种函数调用
“$”到底是个什么东西?
在jquery的源代码中,$函数就是jQuery函数,outro.js有如下申明:
window.jQuery = window.$ = jQuery;
其中jQuery的申明就在core函数里
var jQuery = (function(){ var jQuery = function( selector, context ) { return new jQuery.fn.init( selector, context, rootjQuery ); } //... return jQuery; });
jquery的申明是放在一个闭包里的,这样可以避免变量的名字空间污染。
jquery对象是个什么东西
jquery对象是
new jQuery.fn.init( selector, context, rootjQuery );
生成的。
javascript里,new的操作非常关键,new做的事情可以参考相关文章,简单讲分为以下三步。
var p ={}; jQuery.fn.init.apply(p); p.__proto__ = jQuery.fn.init.prototype;
既然jquery对象是init的new操作生成的,那么init的prototype就至关重要了,于是接下去我们就能看到:
jQuery.fn.init.prototype = jQuery.fn; jQuery.fn = jQuery.prototype = { constructor:jQuery, init: function(selector, context, rootjQuery){ //.... } }
jQuery.fn.init的prototype是jquery.fn,这是一个普通Object,所有jquery对象调用函数时都会通过原型链查找到它,使用jquery.fn里面的方法。这里把jQuery.prototype也设置了一下,目的是使jqueryObj instanceof jQuery的结果是true。
如果调用new jQuery(str),效果和普通的jQuery调用是一样的,因为如果在构造函数中返回了一个对象,new的结果就是这个返回的对象,而不是隐含生成的那个(构造函数里的this)
init函数会根据传入的参数类型不同(一般的类型有html text、dom element、selector),做不同的处理。但最终返回的东西都是一个具有length、splice、push等属性的“假数组”对象,也就是说这个对象具有和数组类似的一些属性,但它的原型(__proto__)和Array.prototype无关,jqueryObj instanceof jQuery的结果也是true
在研究过程中,我同时发现一个有趣的现象:
从firebug中可以看到,jQuery对象是一个数组。这是为什么呢?
其实它返回的仍然是一个object,只不过这个object具有Array的所有属性,比如length、slice、splice等等,是一个”假数组”,而firebug把这个“假数组”当成了真数组显示。经过我实验,我发现firebug会把有length和splice两个属性的object认成是Array。jquery对象上还有一个toArray方法,用于把这个假数组转换成真数组。
综上所述,jquery对象是一个“假数组”,它的原型对象是jQuery.fn。
如何扩展jquery的方法
core中还可以找到extend函数的定义
jQuery.extend = jQuery.fn.extend = function() { //.... }
它可以往jQuery或者jQuery.fn里面插入新的对象,从而达到扩展jQuery函数库的目的。可以想见,直接往jQuery.fn里写东西,和用extend是一样的。(ps:extend还可以用来扩展普通的对象,而不仅仅是扩展jQuery和jQuery.fn)
jquery是如何实现链式调用的
链式调用是jquery一大特色,用链式调用写出的代码非常简洁,它的实现方式也体现在core中。需要实现链式调用的函数,都必须返回一个jquery对象。可以链式调用的方法有两种,一种不会改变jquery当前处理的对象,另一种会改变。
不会改表jquery对象的方法,在一系列处理完成之后会返回this,即当前处理的对象,以进行下一次的调用。
会改变jquery对象的方法,如slice、find等,需要调用pushStack方法新生成一个jquery对象,并返回新生成的jquery对象。pushStack会确保新的jquery对象会具有正确的selector属性。和老对象同样的context。老的jquery对象会保存在prevObject对象中,调用end()就会返回老的jquery对象了。
jQuery的core中还有很多常用的工具函数,会在其他部分的实现中用到,用到了再讲吧