jQuery源码学习笔记五(转)

在正式深入jQuery的核心功能选择器之前,还有一些方法,基本都是数组方法,用于遴选更具体的需要,如获得某个元素的所有祖选元素啦,等等。接着是其缓存机制data。

001.   //去除两边的空白
002.   trim: function( text ) {
003.     return (text || "").replace( /^\s+|\s+$/g, "" );
004.   },
005.   //转换成数组,很大众的方法
006.   makeArray: function( array ) {
007.     var ret = [];
008.     if( array != null ){
009.       var i = array.length;
010.       // The window, strings (and functions) also have 'length'
011.       if( i == null || typeof array === "string" || jQuery.isFunction(array) || array.setInterval )
012.         ret[0] = array;//就只有一元素
013.       else
014.         while( i )//处理数组
015.           ret[--i] = array[i];
016.     }
017.     return ret;
018.   },
019.   //判断是否在数组中,类似indexOf
020.   inArray: function( elem, array ) {
021.     for ( var i = 0, length = array.length; i < length; i++ )
022.     // Use === because on IE, window == document
023.       if ( array[ i ] === elem )
024.         return i;
025.     return -1;
026.   },
027.   //把新元素或第二个数组加入第一个数组中
028.   //类似数组的concat
029.   merge: function( first, second ) {
030.     // We have to loop this way because IE & Opera overwrite the length
031.     // expando of getElementsByTagName
032.     var i = 0, elem, pos = first.length;
033.     // Also, we need to make sure that the correct elements are being returned
034.     // (IE returns comment nodes in a '*' query)
035.     if ( !jQuery.support.getAll ) {
036.       while ( (elem = second[ i++ ]) != null )
037.         if ( elem.nodeType != 8 )
038.           first[ pos++ ] = elem;
039.     } else
040.       while ( (elem = second[ i++ ]) != null )
041.         first[ pos++ ] = elem;
042.     return first;
043.   },
044.   //过滤重复元素,用done这个普通对象做过滤器(因为键如果同名将被覆盖掉)
045.   unique: function( array ) {
046.     var ret = [], done = {};
047.     try {
048.       for ( var i = 0, length = array.length; i < length; i++ ) {
049.         var id = jQuery.data( array[ i ] );
050.         if ( !done[ id ] ) {
051.           done[ id ] = true;
052.           ret.push( array[ i ] );
053.         }
054.       }
055.     } catch( e ) {
056.       ret = array;
057.     }
058.     return ret;
059.   },
060.   //类似数组的filter,这方法起得真不好,通常这都是与正则有关的……
061.   //$.grep( [0,1,2], function(n,i){
062.   //  return n > 0;
063.   //});
064.   //[1, 2]
065.   grep: function( elems, callback, inv ) {
066.     var ret = [];
067.     // Go through the array, only saving the items
068.     // that pass the validator function
069.     //写法很特别,callback之前的!是为了防止回调函数没有返回值
070.     //javascript默认没有返回值的函数都返回undefined,这样一搞
071.     //就变成true,原来返回true的变成false,我们需要负负得正,中和一下
072.     //于是!=出场了,而inv也是未必存在的,用!强制转换成布尔
073.     for ( var i = 0, length = elems.length; i < length; i++ )
074.       if ( !inv != !callback( elems[ i ], i ) )
075.         ret.push( elems[ i ] );
076.     return ret;
077.   },
078.   //就是数组中的map
079.   map: function( elems, callback ) {
080.     var ret = [];
081.     // Go through the array, translating each of the items to their
082.     // new value (or values).
083.     for ( var i = 0, length = elems.length; i < length; i++ ) {
084.       var value = callback( elems[ i ], i );
085.       if ( value != null )
086.         ret[ ret.length ] = value;
087.     }
088.     return ret.concat.apply( [], ret );
089.   }
090. });
091. // jQuery.browser下面的方法已经被废弃了,这些都是为兼容以前的版本与插件用
092. var userAgent = navigator.userAgent.toLowerCase();
093. // Figure out what browser is being used
094. jQuery.browser = {
095.   version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [0,'0'])[1],
096.   safari: /webkit/.test( userAgent ),
097.   opera: /opera/.test( userAgent ),
098.   msie: /msie/.test( userAgent ) && !/opera/.test( userAgent ),
099.   mozilla: /mozilla/.test( userAgent ) && !/(compatible|webkit)/.test( userAgent )
100. };
101. //把以下方法parent,parents,next……添加到jQuery的原型上去,都是一些过滤方法
102. jQuery.each({
103.   parent: function(elem){return elem.parentNode;},
104.   parents: function(elem){return jQuery.dir(elem,"parentNode");},
105.   next: function(elem){return jQuery.nth(elem,2,"nextSibling");},
106.   prev: function(elem){return jQuery.nth(elem,2,"previousSibling");},
107.   nextAll: function(elem){return jQuery.dir(elem,"nextSibling");},
108.   prevAll: function(elem){return jQuery.dir(elem,"previousSibling");},
109.   siblings: function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},
110.   children: function(elem){return jQuery.sibling(elem.firstChild);},
111.   contents: function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}
112. }, function(name, fn){
113.   jQuery.fn[ name ] = function( selector ) {//方法体
114.     var ret = jQuery.map( this, fn );
115.     if ( selector && typeof selector == "string" )
116.       ret = jQuery.multiFilter( selector, ret );
117.     return this.pushStack( jQuery.unique( ret ), name, selector );
118.   };
119. });
120. //把以下方法appendTo,prependTo,insertBefore……添加到jQuery的原型上去,
121. //利用已有的append,prepend……方法构建
122. jQuery.each({
123.   appendTo: "append",
124.   prependTo: "prepend",
125.   insertBefore: "before",
126.   insertAfter: "after",
127.   replaceAll: "replaceWith"
128. }, function(name, original){
129.   jQuery.fn[ name ] = function( selector ) {
130.     var ret = [], insert = jQuery( selector );
131.     for ( var i = 0, l = insert.length; i < l; i++ ) {
132.       var elems = (i > 0 ? this.clone(true) : this).get();
133.       jQuery.fn[ original ].apply( jQuery(insert[i]), elems );
134.       ret = ret.concat( elems );
135.     }
136.     return this.pushStack( ret, name, selector );
137.   };
138. });
139.  //一些重要常用的静态方法
140.   jQuery.each({
141.     removeAttr: function( name ) {
142.       jQuery.attr( this, name, "" );
143.       if (this.nodeType == 1)
144.         this.removeAttribute( name );
145.     },
146.     addClass: function( classNames ) {
147.       jQuery.className.add( this, classNames );
148.     },
149.     removeClass: function( classNames ) {
150.       jQuery.className.remove( this, classNames );
151.     },
152.     toggleClass: function( classNames, state ) {
153.       if( typeof state !== "boolean" )
154.         state = !jQuery.className.has( this, classNames );
155.       jQuery.className[ state ? "add" : "remove" ]( this, classNames );
156.     },
157.     remove: function( selector ) {
158.       if ( !selector || jQuery.filter( selector, [ this ] ).length ) {
159.         // Prevent memory leaks
160.         jQuery( "*", this ).add([this]).each(function(){
161.           jQuery.event.remove(this);//★★★★★
162.           jQuery.removeData(this);
163.         });
164.         if (this.parentNode)
165.           this.parentNode.removeChild( this );
166.       }
167.     },
168.     empty: function() {
169.       // Remove element nodes and prevent memory leaks
170.       jQuery(this).children().remove();
171.       // Remove any remaining nodes
172.       while ( this.firstChild )
173.         this.removeChild( this.firstChild );
174.     }
175.   }, function(name, fn){
176.     jQuery.fn[ name ] = function(){
177.       return this.each( fn, arguments );
178.     };
179.   });
180.   //将带单位的数值去掉单位
181.   // Helper function used by the dimensions and offset modules
182.   function num(elem, prop) {
183.     return elem[0] && parseInt( jQuery.curCSS(elem[0], prop, true), 10 ) || 0;
184.   }

接着下来看jQuery的缓存机制,jQuery的性能很大部分依仗于它。

001. var expando = "jQuery" + now(), uuid = 0, windowData = {};
002. jQuery.extend({
003.   cache: {},
004.   data: function( elem, name, data ) {
005.     //坚决不染指window
006.     elem = elem == window ?
007.       windowData :
008.       elem;
009.     //在elem上设置一个变量
010.     var id = elem[ expando ];
011.     // Compute a unique ID for the element
012.     if ( !id )
013.     //  同时为id,elem[expando]赋值,值为单一数字
014.       id = elem[ expando ] = ++uuid;
015.     // Only generate the data cache if we're
016.     // trying to access or manipulate it
017.     if ( name && !jQuery.cache[ id ] )
018.     //在jQuery.cache上开辟一个对象,专门用于储存与那个elem有关的东西
019.       jQuery.cache[ id ] = {};
020.     // Prevent overriding the named cache with undefined values
021.     if ( data !== undefined )//data必须定义
022.       jQuery.cache[ id ][ name ] = data;
023.     // Return the named cache data, or the ID for the element
024.     //根据第二个参数是否存在决定返回的是缓存数据还是element的特别ID
025.     return name ?
026.       jQuery.cache[ id ][ name ] :
027.       id;
028.   },
029.   //移除缓存数据
030.   removeData: function( elem, name ) {
031.     elem = elem == window ?
032.       windowData :
033.       elem;
034.     var id = elem[ expando ];
035.     // If we want to remove a specific section of the element's data
036.     if ( name ) {
037.       if ( jQuery.cache[ id ] ) {
038.         // Remove the section of cache data
039.         delete jQuery.cache[ id ][ name ];
040.         // If we've removed all the data, remove the element's cache
041.         name = "";
042.         for ( name in jQuery.cache[ id ] )
043.           break;
044.         if ( !name )
045.           jQuery.removeData( elem );
046.       }
047.       // Otherwise, we want to remove all of the element's data
048.     } else {
049.       // Clean up the element expando
050.       try {
051.         //IE不能直接用delete去移除,要用removeAttribute
052.         delete elem[ expando ];
053.       } catch(e){
054.         // IE has trouble directly removing the expando
055.         // but it's ok with using removeAttribute
056.         if ( elem.removeAttribute )
057.           elem.removeAttribute( expando );
058.       }
059.       // Completely remove the data cache
060.       //用缓存体中把其索引值也移掉
061.       delete jQuery.cache[ id ];
062.     }
063.   },
064.   //缓存元素的类组数属性
065.   //可读写
066.   queue: function( elem, type, data ) {
067.     if ( elem ){
068.       type = (type || "fx") + "queue";
069.       var q = jQuery.data( elem, type );
070.       if ( !q || jQuery.isArray(data) )
071.       //q是数组
072.         q = jQuery.data( elem, type, jQuery.makeArray(data) );
073.       else if( data )
074.         q.push( data );
075.     }
076.     return q;
077.   },
078.   //对元素的类数组缓存进行dequeue(也就是shift)
079.   dequeue: function( elem, type ){
080.     var queue = jQuery.queue( elem, type ),
081.     fn = queue.shift();
082.     if( !type || type === "fx" )
083.       fn = queue[0];
084.     if( fn !== undefined )
085.       fn.call(elem);
086.   }
087. });
088. //让jQuery对象也能获得这种缓存能力
089. //都是用上面静态方法实现,最终的缓存体还是jQuery.cache
090. jQuery.fn.extend({
091.   data: function( key, value ){
092.     var parts = key.split(".");
093.     parts[1] = parts[1] ? "." + parts[1] : "";
094.     if ( value === undefined ) {
095.       var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
096.       if ( data === undefined && this.length )
097.         data = jQuery.data( this[0], key );
098.       return data === undefined && parts[1] ?
099.         this.data( parts[0] ) :
100.         data;
101.     } else
102.       return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function(){
103.         jQuery.data( this, key, value );
104.       });
105.   },
106.   removeData: function( key ){
107.     return this.each(function(){
108.       jQuery.removeData( this, key );
109.     });
110.   },
111.   queue: function(type, data){
112.     if ( typeof type !== "string" ) {
113.       data = type;
114.       type = "fx";
115.     }
116.     if ( data === undefined )
117.       return jQuery.queue( this[0], type );
118.     return this.each(function(){
119.       var queue = jQuery.queue( this, type, data );
120.       if( type == "fx" && queue.length == 1 )
121.         queue[0].call(this);
122.     });
123.   },
124.   dequeue: function(type){
125.     return this.each(function(){
126.       jQuery.dequeue( this, type );
127.     });
128.   }
129. });

转载于:https://www.cnblogs.com/dongpo888/archive/2009/11/22/1608097.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值