jquery 类 源码 分析(转载)

来源:互联网 发布:由丑变漂亮.知乎 编辑:程序博客网 时间:2024/04/29 13:41

先看core.js文件:
var jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
  return new jQuery.fn.init( selector, context );//
},
jQuery是一个Function。在JavaScript中,Function是一种特殊的对象,这个对象可以有自己的属性。
但是JQuery(parameters)方法调用的结果却是一个jQuery.fn.init对象。注意此处的new Function用法,实际上返回了一个对象实例。
这个对象实例的类型是jQuery.fn.init,而不是JQuery。--至少现在不是。

往下看:
jQuery.fn = jQuery.prototype = {init:function (){},...}
这一段意味着,jQuery.fn 和jQuery.prototype是一样的,都是jQuery的prototype。prototype是JavaScript实现类型继承的机制。简单地说,jQuery.prototype这个对象有的属性,jQuery对象实例也继承过来了。注意上文提到过,jQuery是一个方法,也就是Function对象。jQuery和jQuery对象实例是不同的。jQuery对象实例是调用new jQuery(..)产生的。jQuery作为一个Function对象,是不能继承jQuery.prototype的属性的,Function对象有自己的prototype。也就是说,jQuery.init是undefined,这点应该没有问题的。但是var x=new jQuery();x就有了jQuery.prototype这个对象的所有属性,包括init方法,length等属性。

jQuery.fn.init.prototype = jQuery.fn;
这句话很关键。
jQuery是一个方法,jQuery(...)方法调用的结果是一个jQuery.fn.init对象实例,这是上文提到的。上面这句话意味着,jQuery.fn.init对象实例的父类是jQuery.fn。也就是说,jQuery.fn有的属性,jQuery.fn.init的对象实例也有。这说明,如果var x=jQuery(xxx);那么x将有jQuery.fn对象的所有属性,包括init方法,length属性等。跟var x=new jQuery()的效果一样。这样之后,发现,jQuery方法就是一个工厂方法,产生jQuery对象实例(其实是jQuery.fn.init对象实例,但是,既然jQuery.fn.init对象实例的父类是jQuery.prototype也就是jQuery对象实例的父类,意味着jQuery对象实例和jQuery.fn.init对象实例有共同的父类,就把它们当作是一样的吧)。

继续:
jQuery.extend = jQuery.fn.extend = function() {...}
这里定义了jQuery核心的一个重要的extend方法。这里不厌其烦地再提一遍,jQuery是一个Function对象,这句代码之后,这个Function对象有了一个新的属性。而所有jQuery的实例,也就是工厂方法jQuery(...)或者new jQuery产生的对象都具有了extend方法。
这个extend的作用是,扩展jQuery对象实例的功能,这成为jQuery插件机制的基础。当然,也可以直接拿来用。jQuery.extend(object1,object2)之后,object1的属性融合了object2的属性,而object2保持不变。

jQuery.extend({noConflict:function(){...},...})
这句的作用是,扩展jQuery这个Function对象的属性,使他具有了熟悉的noConflict等方法,把这些方法当作是工具方法吧,因为jQuery框架的主角是jQuery实例。

browserMatch = jQuery.uaMatch( userAgent );
这是jQuery用来做浏览器检测的。这个功能主要通过navigator.userAgent字符串来判断的,仅供参考。

下来:
rootjQuery = jQuery(document);
这个jQuery的实例在core.js内部使用,并没有在其他地方暴露。

最后一句:
window.jQuery = window.$ = jQuery;
将jQuery(即$)这个Function对象暴露在全局范围内。

以上是粗略的分析。

下面进行更细致的分析。
jQuery.fn.init是核心方法之一。
// Handle $(DOMElement)
if ( selector.nodeType ) {
??this.context = this[0] = selector;
??this.length = 1;
??return this;
}
每一个jQuery对象实例都有context和selector,length属性。而且,每一个jQuery对象都是一个索引"数组",这个数组里面包含的内容是DOM元素。这是很重要的,因为jQuery的一个设计理念就是,获取DOM元素(现在发现存在索引数组里面),并且操作这些DOM元素(manipulation.js和traversing.js等等负责这些任务)。
无疑,上面的代码效率很高。

...
} else if ( jQuery.isFunction( selector ) ) {
return rootjQuery.ready( selector );
}
jQuery(function(){...})意思是在DOM加载完之后执行一个方法。

pushStack方法,在执行eq,first,last等方法之后,调用end之后可以回退到之前的jQuery对象。


jQuery.fn.extend(.....
map: function( callback ) {
return this.pushStack( jQuery.map(this, function( elem, i ) {
return callback.call( elem, i, elem );
}));
},
这个map方法直接把原来jQuery对象里保存的DOM元素转换成别的元素,通过callback方法。pushStack在此意味着这map之后还可以回退到原来的jQuery对象实例。

jQuery.extend(.....
noConflict: function( deep ) {
window.$ = _$;

if ( deep ) {
window.jQuery = _jQuery;
}

return jQuery;
},
这个是为了防止冲突。
注意在一开始的时候,已经保存了原来可能已经存在的jQuery,$变量:
// Map over jQuery in case of overwrite
_jQuery = window.jQuery,

// Map over the $ in case of overwrite
_$ = window.$,
此处将其还原。

makeArray(arr),将一个Array-like的元素变成一个Array。如果arr含有length,并且含有索引属性,转化就是有意义的。

merge(first,second),将数组(或者类似数组的对象)second的元素拷到first数组的最后。

grep: function( elems, callback, inv ) 通过callback过滤掉elems中的某些元素。callback的返回值将被标准化为true或false。如果callback的返回值和inv相等,相应的元素将被过滤掉。inv默认是false。

map: function( elems, callback, arg ) ?将elems中的元素用callback(value,index)转化,然后返回转化后的数组,如果callback的返回值是null,相应元素将被过滤。

proxy: function( fn, proxy, thisObject ) 将方法fn的执行环境(this)设成proxy,使用fn.call(proxy,arguments)实现。
原创粉丝点击