在正式深入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.});
 posted on 2009-11-22 16:11  dongpo  阅读(336)  评论(0编辑  收藏  举报