在正式深入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.
});