之前有前辈和我说学习JavaScript的知识点,尤其是比较抽象和深奥的点,可以看下优秀的框架源码,所以今天开始拜读jquery的源码,不仅是巩固jquery的用法和每个方法的实现,更重要的是学习框架的设计模式以及设计缘由。
借鉴和参考别人的理解:
jQuery的总体框架:
(function(window,undefined){
var jQuery=function(selector,context){
//...
};
//工具方法utilities
//回调函数 callbacks
//异步队列 Defered Object
//浏览器功能测试 Support
//数据缓存 Data
//队列 Queue
//属性操作 Attributes
//事件系统 Events
//选择器 Sizzle
//DOM遍历 Traversing
//DOM操作 Manipulation
//样式操作 CSS
//异步请求 Ajax
//动画 Animation
//坐标 offset,尺寸 Dimensions
window.jQuery=window.$=jQuery;
}})(window);
关于上述代码,解释如下:
1.jQuery的整体代码包裹在一个立即执行的自调用匿名的函数中,这样可以尽量减少和其他第三方库的干扰;
2,在上述代码最后,将jQuery对象添加到全局window上,并为之设置变量$,从而使得可以在外界访问jQuery;
3,为自调用匿名函数设置参数window,并传入参数window,这样一方面可以缩短作用域链,可以尽快访问到window;另一方面便于代码压缩;
4,为自动用匿名函数设置参数undefined,一方面可以缩短查找Undefined的作用域链,另一方面可防止undefined在外界被修改。
jquery.fn执行jquery的原型对象,共享方法,让我们更好理解,jQuery是一个封装得非常好的‘类’,比如我们用语句 $("#btn1") 会生成一个 jQuery类的实例。
以下是阅读后做的笔记,其中难以理解的是pushStack 方法,pushStack() 函数用于将一个DOM元素集合加入到jQuery栈, 主要是用于内部函数。
//jquery.fn执行jquery的原型对象
jQuery.fn = jQuery.prototype = {
// The current version of jQuery being used
jquery: version,
constructor: jQuery,
// The default length of a jQuery object is 0
length: 0,
//toArray:取回包含在该jquery集合中的所有元素,作为一个数组
//alert( $( "li" ).toArray() );调用这个方法,所有的匹配的DOM节点都会返回,包含在一个标准数组中:[<li id="foo">, <li id="bar">]
//arr.slice.call(this),call方法调用一个对象的一个方法,以另一个对象替换当前对象。
//this是jquery.fn的实例,toArray方法完全继承了slice的方法和属性
toArray: function() {
return slice.call( this );
},
// Get the Nth element in the matched element set OR
// Get the whole matched element set as a clean array
//get方法没有参数则返回所有元素的一个数组,同toArray方法
//有参数则取回jquery对象所匹配的DOM元素,例如console.log( $( "li" ).get( 0 ) );=><li id="bar">
get: function( num ) {
// Return all the elements in a clean array
if ( num == null ) {
return slice.call( this );
}
// Return just the one element from the set
//console.log( $( "li" )[ 0 ] );的句法无法用负数索引,负索引从匹配元素的末尾开始计数
//num为负数则转换为正数,get(-1)=>get(2)
return num < 0 ? this[ num + this.length ] : this[ num ];
},
// Take an array of elements and push it onto the stack
// (returning the new matched element set)
//pushStack把获取的元素数组放到栈中返回一个新的被匹配的数组
//在执行jquery构造函数之后会产生一个实例对象,里面放着匹配到的元素,当使用这一个方法时
//就会再新建一个空的jquery对象,然后再把调用这个方法的对象匹配到的元素放到栈中,就是一
//个数组通过一个指针指向调用此方法的对象,这样就是一个链式栈可以不断扩展
pushStack: function( elems ) {
// Build a new jQuery matched element set
//构造一个新的空jquery对象ret,this.constructor 指向构造函数 jQuery()
//$.merge() 函数用于合并两个数组内容到第一个数组
var ret = jQuery.merge( this.constructor(), elems );
// Add the old object onto the stack (as a reference)
//在新对象中添加这么一个属性来指向当前的jQuery对象
//merge产生的jQuery对象设置一个prevObject属性,并将当前(merge之前的)的对象赋值给prevObject
ret.prevObject = this;
// Return the newly-formed element set
return ret;
},
// Execute a callback for every element in the matched set.
//迭代一个jQuery对象,针对每个匹配的元素执行一个函数
/*例如:
$( "li" ).each(function( index ) {
console.log( index + ": " + $( this ).text() );
});
*/
each: function( callback ) {
return jQuery.each( this, callback );
},
//将一组数组转换为其他数组
map: function( callback ) {
return this.pushStack( jQuery.map( this, function( elem, i ) {
return callback.call( elem, i, elem );
} ) );
},
slice: function() {
return this.pushStack( slice.apply( this, arguments ) );
},
first: function() {
return this.eq( 0 );
},
last: function() {
return this.eq( -1 );
},
eq: function( i ) {
//若i=-1,len=3,则j=0+3=3,即最后一位索引为-1,第一位索引为0
var len = this.length,
j = +i + ( i < 0 ? len : 0 );
return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );
},
//end返回当前jquery对象的上一个状态
// 所有通过pushStack方法获得的jQuery对象都可以通过end方法返回之前的状态
// 如果有preObject对象则返回该对象,否则调用构造函数返回jQuery的空对象
end: function() {
return this.prevObject || this.constructor();
},
// For internal use only.
// Behaves like an Array's method, not like a jQuery method.
//javascript原生方法
push: push,
sort: arr.sort,
splice: arr.splice
};