还有一点,jQuery.prototype第一个阶级的能力部署就完成了。就像一个茧,jQuery对象包裹着一个或复数个DOM对象,jQuery对象的能力来自其prototype,而其prototype的方法则是jQuery.prototype的一个副本。
01.
//对当前jQuery中的DOM进行slice操作,并把参数传入this.prevObject中
02.
slice:
function
() {
03.
return
this
.pushStack( Array.prototype.slice.apply(
this
, arguments ),
04.
"slice"
, Array.prototype.slice.call(arguments).join(
","
) );
05.
},
06.
//与上面差不多
07.
map:
function
( callback ) {
08.
return
this
.pushStack( jQuery.map(
this
,
function
(elem, i){
09.
return
callback.call( elem, i, elem );
10.
}));
11.
},
12.
//把之前放入this.preveObject的DOM数组取出来,加入现在的DOM数组中
13.
andSelf:
function
() {
14.
return
this
.add(
this
.prevObject );
15.
},
16.
17.
domManip:
function
( args, table, callback ) {
18.
if
(
this
[0] ) {
19.
//如果jQuery对象有DOM元素,则取得其文档对象,调用其createDocumentFragment方法
20.
var
fragment = (
this
[0].ownerDocument ||
this
[0]).createDocumentFragment(),
21.
//这里的args恒为arguments对象,用jQuery.clean获得纯DOM元素数组
22.
scripts = jQuery.clean( args, (
this
[0].ownerDocument ||
this
[0]), fragment ),
23.
first = fragment.firstChild;
24.
25.
if
( first )
26.
for
(
var
i = 0, l =
this
.length; i < l; i++ )
27.
//callback传入一个元素与一个文档
28.
callback.call( root(
this
[i], first),
this
.length > 1 || i > 0 ?
29.
fragment.cloneNode(
true
) : fragment );
30.
if
( scripts )
31.
jQuery.each( scripts, evalScript );
32.
}
33.
34.
return
this
;
35.
//root用于检测当前元素是否为table,是就检测tbody是否存在,没有则创建
36.
function
root( elem, cur ) {
37.
return
table && jQuery.nodeName(elem,
"table"
) && jQuery.nodeName(cur,
"tr"
) ?
38.
(elem.getElementsByTagName(
"tbody"
)[0] ||
39.
elem.appendChild(elem.ownerDocument.createElement(
"tbody"
))) :
40.
elem;
41.
}
42.
}
43.
};
44.
//把jQuery.prototype的能力加持到jQuery.prototype.init.prototype上
45.
jQuery.fn.init.prototype = jQuery.fn;
至此,jQuery对象第一阶级的能力就告一段落,要不对象体就很长。下面添加新的能力时就用jQuery.extend求添加,就像Prototype的Object.extend,mootool的Native.implement,Base2的Base.extend,Ext的apply,凡此种种,把一个属性包或独立的方法名与方法体作为参数加入目标对象中。因为光是在对象体搞(这里是原型),没有私有变量可言,有时我们很需要这些作为胶水在连接我们的方法,因此打散写有打散写的好处。更何况,jQuery类库都是整个包围在一个闭包中,这些散乱的函数与变量不会逃逸到外面去,与我们的业务逻辑中用的函数或变量发生命名冲突。
01.
//jQuery的能力扩展的核心函数
02.
//这要求存在继承者与授与者两方,一般来说继承者在左,授与者在右,授与者通常是一个简单的属性包
03.
jQuery.extend = jQuery.fn.extend =
function
() {
04.
// copy reference to target object
05.
var
target = arguments[0] || {}, i = 1, length = arguments.length, deep =
false
, options;
06.
// Handle a deep copy situation
07.
if
(
typeof
target ===
"boolean"
) {
//如果第一个参数是布尔值
08.
deep = target;
09.
target = arguments[1] || {};
//设置继承者
10.
// skip the boolean and the target
11.
i = 2;
12.
}
13.
// Handle case when target is a string or something (possible in deep copy)
14.
if
(
typeof
target !==
"object"
&& !jQuery.isFunction(target) )
15.
target = {};
16.
//如果没有指定要继承能力的对象,则扩展到自身
17.
// extend jQuery itself if only one argument is passed
18.
if
( length == i ) {
19.
target =
this
;
20.
--i;
21.
}
22.
for
( ; i < length; i++ )
23.
// Only deal with non-null/undefined values
24.
if
( (options = arguments[ i ]) !=
null
)
25.
// Extend the base object
26.
for
(
var
name
in
options ) {
27.
var
src = target[ name ], copy = options[ name ];
28.
29.
// Prevent never-ending loop
30.
if
( target === copy )
31.
continue
;
32.
//如果是深复制,某对象的属性也是对象并且不是HTMLElement,则把它逐一分解拷到继承者
33.
// Recurse if we're merging object values
34.
if
( deep && copy &&
typeof
copy ===
"object"
&& !copy.nodeType )
35.
target[ name ] = jQuery.extend( deep,
36.
// Never move original objects, clone them
37.
src || ( copy.length !=
null
? [ ] : { } )
38.
, copy );
39.
// Don't bring in undefined values
40.
else
if
( copy !== undefined )
41.
target[ name ] = copy;
42.
}
43.
// Return the modified object
44.
return
target;
45.
};
定义几个位于闭包的顶层变量,准备新一轮的功能扩展
1.
// exclude the following css properties to add px
2.
//将转换成px单位
3.
var
exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i,
4.
// cache defaultView
5.
defaultView = document.defaultView || {},
6.
toString = Object.prototype.toString;
001.
//第二轮能力扩展,这次是添加一系列静态方法
002.
jQuery.extend({
003.
004.
noConflict:
function
( deep ) {
005.
//引入jQuery类库后,闭包外面的window.$与window.jQuery都储存着一个函数,
006.
//它是用来生成jQuery对象或在domReady后执行里面的函数的
007.
//回顾最上面的代码,在还没有把function赋给它们时,_jQuery与_$已经被赋值了,
008.
//因此它们俩的值一定必然是undefined
009.
//因此这种放弃控制权的技术很简单,就是用undefined把window.$里面的jQuery系的函数清除掉
010.
//这时Prototype或mootools的$就可以明门正娶了
011.
window.$ = _$;
//相当window.$ = undefined
012.
//如果连你的程序也有一个叫jQuery的东西呢,jQuery可以大方地连这个也让渡出去
013.
//这时就要为noConflict添加一个布尔值,为true
014.
if
( deep )
015.
//但我们必须用一个东西要接纳jQuery对象与jQuery的入口函数
016.
//闭包里面的东西除非被window等宿主对象引用,否则就是不可见的
017.
//因此我们把闭包里面的jQuery return出去,外面用一个变量接纳就是
018.
window.jQuery = _jQuery;
//相当window.jQuery = undefined
019.
return
jQuery;
020.
},
021.
022.
//外国近年来新发现的检测技术toString
023.
isFunction:
function
( obj ) {
024.
return
toString.call(obj) ===
"[object Function]"
;
025.
},
026.
027.
isArray:
function
( obj ) {
028.
return
toString.call(obj) ===
"[object Array]"
;
029.
},
030.
031.
// check if an element is in a (or is an) XML document
032.
//检测是否为XML的文档对象
033.
isXMLDoc:
function
( elem ) {
034.
return
elem.nodeType === 9 && elem.documentElement.nodeName !==
"HTML"
||
035.
!!elem.ownerDocument && jQuery.isXMLDoc( elem.ownerDocument );
036.
},
037.
038.
// Evalulates a script in a global context
039.
//把一段文本解析成脚本,利用script元素的text属性
040.
globalEval:
function
( data ) {
041.
if
( data && /\S/.test(data) ) {
042.
// Inspired by code by Andrea Giammarchi
044.
var
head = document.getElementsByTagName(
"head"
)[0] || document.documentElement,
045.
script = document.createElement(
"script"
);
046.
//自行创建一个script元素,如果支持text属性则直接赋,不支持就用标准方法在里面添加文本
047.
script.type =
"text/javascript"
;
048.
if
( jQuery.support.scriptEval )
049.
script.appendChild( document.createTextNode( data ) );
050.
else
051.
script.text = data;
052.
// Use insertBefore instead of appendChild to circumvent an IE6 bug.
053.
// This arises when a base node is used (#2709).
054.
head.insertBefore( script, head.firstChild );
055.
head.removeChild( script );
056.
}
057.
},
058.
//检测elem的nodeName是否等于第二个参数name
059.
nodeName:
function
( elem, name ) {
060.
return
elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase();
061.
},
062.
// args is for internal usage only
063.
each:
function
( object, callback, args ) {
064.
var
name, i = 0, length = object.length;
065.
066.
if
( args ) {
067.
if
( length === undefined ) {
068.
//如果是对象就对其值调用方法,如果调用函数没有返回值或返回false就跳出循环
069.
for
( name
in
object )
070.
if
( callback.apply( object[ name ], args ) ===
false
)
071.
break
;
072.
}
else
073.
//如果是数组
074.
for
( ; i < length; )
075.
if
( callback.apply( object[ i++ ], args ) ===
false
)
076.
break
;
077.
//同上,只不过没有传入第三个参数
078.
// A special, fast, case for the most common use of each
079.
}
else
{
080.
if
( length === undefined ) {
081.
for
( name
in
object )
082.
if
( callback.call( object[ name ], name, object[ name ] ) ===
false
)
083.
break
;
084.
}
else
085.
for
(
var
value = object[0];
086.
i < length && callback.call( value, i, value ) !==
false
; value = object[++i] ){}
087.
}
088.
089.
return
object;
090.
},
091.
//用于返回各种属性
092.
prop:
function
( elem, value, type, i, name ) {
093.
// Handle executable functions
094.
if
( jQuery.isFunction( value ) )
095.
value = value.call( elem, i );
096.
097.
// Handle passing in a number to a CSS property
098.
return
typeof
value ===
"number"
&& type ==
"curCSS"
&& !exclude.test( name ) ?
099.
value +
"px"
:
100.
value;
101.
},
接着下来就是对样式的操作了,样式在WEB开发中非常重要,我留在下一节重点讲!