jQuery源码学习笔记五
在正式深入jQuery的核心功能选择器之前,还有一些方法,基本都是数组方法,用于遴选更具体的需求,如获得某个元素的所有祖选元素啦,等等。接着是其缓存机制data。
//@author 司徒正美|なさみ|cheng http://www.cnblogs.com/rubylouvre/ All rights reserved //去除两边的空白 trim: function ( text ) { return (text || "" ).replace( /^\s+|\s+$/g, "" ); }, //转换成数组,很大众的方法 makeArray: function ( array ) { var ret = []; if ( array != null ){ var i = array.length; // The window, strings (and functions) also have 'length' if ( i == null || typeof array === "string" || jQuery.isFunction(array) || array.setInterval ) ret[0] = array; //就只有一元素 else while ( i ) //处理数组 ret[--i] = array[i]; } return ret; }, //判断是否在数组中,类似indexOf inArray: function ( elem, array ) { for ( var i = 0, length = array.length; i < length; i++ ) // Use === because on IE, window == document if ( array[ i ] === elem ) return i; return -1; }, //把新元素或第二个数组加入第一个数组中 //类似数组的concat merge: function ( first, second ) { // We have to loop this way because IE & Opera overwrite the length // expando of getElementsByTagName var i = 0, elem, pos = first.length; // Also, we need to make sure that the correct elements are being returned // (IE returns comment nodes in a '*' query) if ( !jQuery.support.getAll ) { while ( (elem = second[ i++ ]) != null ) if ( elem.nodeType != 8 ) first[ pos++ ] = elem; } else while ( (elem = second[ i++ ]) != null ) first[ pos++ ] = elem; return first; }, //过滤重复元素,用done这个普通对象做过滤器(因为键如果同名将被覆盖掉) unique: function ( array ) { var ret = [], done = {}; try { for ( var i = 0, length = array.length; i < length; i++ ) { var id = jQuery.data( array[ i ] ); if ( !done[ id ] ) { done[ id ] = true ; ret.push( array[ i ] ); } } } catch ( e ) { ret = array; } return ret; }, //类似数组的filter,这方法起得真不好,通常这都是与正则有关的…… //$.grep( [0,1,2], function(n,i){ // return n > 0; //}); //[1, 2] grep: function ( elems, callback, inv ) { var ret = []; // Go through the array, only saving the items // that pass the validator function //写法很特别,callback之前的!是为了防止回调函数没有返回值 //javascript默认没有返回值的函数都返回undefined,这样一搞 //就变成true,原来返回true的变成false,我们需要负负得正,中和一下 //于是!=出场了,而inv也是未必存在的,用!强制转换成布尔 for ( var i = 0, length = elems.length; i < length; i++ ) if ( !inv != !callback( elems[ i ], i ) ) ret.push( elems[ i ] ); return ret; }, //就是数组中的map map: function ( elems, callback ) { var ret = []; // Go through the array, translating each of the items to their // new value (or values). for ( var i = 0, length = elems.length; i < length; i++ ) { var value = callback( elems[ i ], i ); if ( value != null ) ret[ ret.length ] = value; } return ret.concat.apply( [], ret ); } }); // jQuery.browser下面的方法已经被废弃了,这些都是为兼容以前的版本与插件用 var userAgent = navigator.userAgent.toLowerCase(); // Figure out what browser is being used jQuery.browser = { version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [0, '0' ])[1], safari: /webkit/.test( userAgent ), opera: /opera/.test( userAgent ), msie: /msie/.test( userAgent ) && !/opera/.test( userAgent ), mozilla: /mozilla/.test( userAgent ) && !/(compatible|webkit)/.test( userAgent ) }; //把以下方法parent,parents,next……添加到jQuery的原型上去,都是一些过滤方法 jQuery.each({ parent: function (elem){ return elem.parentNode;}, parents: function (elem){ return jQuery.dir(elem, "parentNode" );}, next: function (elem){ return jQuery.nth(elem,2, "nextSibling" );}, prev: function (elem){ return jQuery.nth(elem,2, "previousSibling" );}, nextAll: function (elem){ return jQuery.dir(elem, "nextSibling" );}, prevAll: function (elem){ return jQuery.dir(elem, "previousSibling" );}, siblings: function (elem){ return jQuery.sibling(elem.parentNode.firstChild,elem);}, children: function (elem){ return jQuery.sibling(elem.firstChild);}, contents: function (elem){ return jQuery.nodeName(elem, "iframe" )?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);} }, function (name, fn){ jQuery.fn[ name ] = function ( selector ) { //方法体 var ret = jQuery.map( this , fn ); if ( selector && typeof selector == "string" ) ret = jQuery.multiFilter( selector, ret ); return this .pushStack( jQuery.unique( ret ), name, selector ); }; }); //把以下方法appendTo,prependTo,insertBefore……添加到jQuery的原型上去, //利用已有的append,prepend……方法构建 jQuery.each({ appendTo: "append" , prependTo: "prepend" , insertBefore: "before" , insertAfter: "after" , replaceAll: "replaceWith" }, function (name, original){ jQuery.fn[ name ] = function ( selector ) { var ret = [], insert = jQuery( selector ); for ( var i = 0, l = insert.length; i < l; i++ ) { var elems = (i > 0 ? this .clone( true ) : this ).get(); jQuery.fn[ original ].apply( jQuery(insert[i]), elems ); ret = ret.concat( elems ); } return this .pushStack( ret, name, selector ); }; }); //一些重要常用的静态方法 jQuery.each({ removeAttr: function ( name ) { jQuery.attr( this , name, "" ); if ( this .nodeType == 1) this .removeAttribute( name ); }, addClass: function ( classNames ) { jQuery.className.add( this , classNames ); }, removeClass: function ( classNames ) { jQuery.className.remove( this , classNames ); }, toggleClass: function ( classNames, state ) { if ( typeof state !== "boolean" ) state = !jQuery.className.has( this , classNames ); jQuery.className[ state ? "add" : "remove" ]( this , classNames ); }, remove: function ( selector ) { if ( !selector || jQuery.filter( selector, [ this ] ).length ) { // Prevent memory leaks jQuery( "*" , this ).add([ this ]).each( function (){ jQuery.event.remove( this ); //★★★★★ jQuery.removeData( this ); }); if ( this .parentNode) this .parentNode.removeChild( this ); } }, empty: function () { // Remove element nodes and prevent memory leaks jQuery( this ).children().remove(); // Remove any remaining nodes while ( this .firstChild ) this .removeChild( this .firstChild ); } }, function (name, fn){ jQuery.fn[ name ] = function (){ return this .each( fn, arguments ); }; }); //将带单位的数值去掉单位 // Helper function used by the dimensions and offset modules function num(elem, prop) { return elem[0] && parseInt( jQuery.curCSS(elem[0], prop, true ), 10 ) || 0; } |
接着下来看jQuery的缓存机制,jQuery的性能很大部分依仗于它。
//@author 司徒正美|RestlessDream|なさみ|cheng http://www.cnblogs.com/rubylouvre/ All rights reserved var expando = "jQuery" + now(), uuid = 0, windowData = {}; jQuery.extend({ cache: {}, data: function ( elem, name, data ) { //坚决不染指window elem = elem == window ? windowData : elem; //在elem上设置一个变量 var id = elem[ expando ]; // Compute a unique ID for the element if ( !id ) // 同时为id,elem[expando]赋值,值为单一数字 id = elem[ expando ] = ++uuid; // Only generate the data cache if we're // trying to access or manipulate it if ( name && !jQuery.cache[ id ] ) //在jQuery.cache上开辟一个对象,专门用于储存与那个elem有关的东西 jQuery.cache[ id ] = {}; // Prevent overriding the named cache with undefined values if ( data !== undefined ) //data必须定义 jQuery.cache[ id ][ name ] = data; // Return the named cache data, or the ID for the element //根据第二个参数是否存在决定返回的是缓存数据还是element的特别ID return name ? jQuery.cache[ id ][ name ] : id; }, //移除缓存数据 removeData: function ( elem, name ) { elem = elem == window ? windowData : elem; var id = elem[ expando ]; // If we want to remove a specific section of the element's data if ( name ) { if ( jQuery.cache[ id ] ) { // Remove the section of cache data delete jQuery.cache[ id ][ name ]; // If we've removed all the data, remove the element's cache name = "" ; for ( name in jQuery.cache[ id ] ) break ; if ( !name ) jQuery.removeData( elem ); } // Otherwise, we want to remove all of the element's data } else { // Clean up the element expando try { //IE不能直接用delete去移除,要用removeAttribute delete elem[ expando ]; } catch (e){ // IE has trouble directly removing the expando // but it's ok with using removeAttribute if ( elem.removeAttribute ) elem.removeAttribute( expando ); } // Completely remove the data cache //用缓存体中把其索引值也移掉 delete jQuery.cache[ id ]; } }, //缓存元素的类组数属性 //可读写 queue: function ( elem, type, data ) { if ( elem ){ type = (type || "fx" ) + "queue" ; var q = jQuery.data( elem, type ); if ( !q || jQuery.isArray(data) ) //q是数组 q = jQuery.data( elem, type, jQuery.makeArray(data) ); else if ( data ) q.push( data ); } return q; }, //对元素的类数组缓存进行dequeue(也就是shift) dequeue: function ( elem, type ){ var queue = jQuery.queue( elem, type ), fn = queue.shift(); if ( !type || type === "fx" ) fn = queue[0]; if ( fn !== undefined ) fn.call(elem); } }); //让jQuery对象也能获得这种缓存能力 //都是用上面静态方法实现,最终的缓存体还是jQuery.cache jQuery.fn.extend({ data: function ( key, value ){ var parts = key.split( "." ); parts[1] = parts[1] ? "." + parts[1] : "" ; if ( value === undefined ) { var data = this .triggerHandler( "getData" + parts[1] + "!" , [parts[0]]); if ( data === undefined && this .length ) data = jQuery.data( this [0], key ); return data === undefined && parts[1] ? this .data( parts[0] ) : data; } else return this .trigger( "setData" + parts[1] + "!" , [parts[0], value]).each( function (){ jQuery.data( this , key, value ); }); }, removeData: function ( key ){ return this .each( function (){ jQuery.removeData( this , key ); }); }, queue: function (type, data){ if ( typeof type !== "string" ) { data = type; type = "fx" ; } if ( data === undefined ) return jQuery.queue( this [0], type ); return this .each( function (){ var queue = jQuery.queue( this , type, data ); if ( type == "fx" && queue.length == 1 ) queue[0].call( this ); }); }, dequeue: function (type){ return this .each( function (){ jQuery.dequeue( this , type ); }); } }); |
如果您觉得此文有帮助,可以打赏点钱给我支付宝1669866773@qq.com ,或扫描二维码


机器瞎学/数据掩埋/模式混淆/人工智障/深度遗忘/神经掉线/计算机幻觉/专注单身二十五年
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?