@@ -10,6 +10,8 @@ var runtil = /Until$/,
1010 prev : true
1111 } ;
1212
13+ // 为 jQuery 实例对象提供扩展方法:
14+ // find, has, not, filter, is, closest, index, add, addBack
1315jQuery . fn . extend ( {
1416 find : function ( selector ) {
1517 var i , l , length , n , r , ret ,
@@ -68,7 +70,9 @@ jQuery.fn.extend({
6870 filter : function ( selector ) {
6971 return this . pushStack ( winnow ( this , selector , true ) , "filter" , selector ) ;
7072 } ,
71-
73+ /**
74+ * @desc http://api.jquery.com/is/ 涉及Sizzle,不在此次分析范畴
75+ */
7276 is : function ( selector ) {
7377 return ! ! selector && (
7478 typeof selector === "string" ?
@@ -144,22 +148,31 @@ jQuery.fn.extend({
144148 }
145149} ) ;
146150
151+ // andSelf 方法名以后将 addBack 替换,所以请使用 addBack,
152+ // 这两个方法在官方 API 文档里的区别是:前者不接受参数,后者可选接受一个查找参数
147153jQuery . fn . andSelf = jQuery . fn . addBack ;
148154
149155// A painfully simple check to see if an element is disconnected
150156// from a document (should be improved, where feasible).
157+ // 检查某个节点是否在 document 中
158+ // DOCUMENT_FRAGMENT_NODE(11)
151159function isDisconnected ( node ) {
152160 return ! node || ! node . parentNode || node . parentNode . nodeType === 11 ;
153161}
154-
162+ /**
163+ * @desc 查找某个元素的兄元素或弟元素
164+ * @param cur {Element} 出发点元素
165+ * @param dir {string } 方向 'previousSibling' or 'nextSibling'
166+ * @return {Element }
167+ */
155168function sibling ( cur , dir ) {
156169 do {
157170 cur = cur [ dir ] ;
158- } while ( cur && cur . nodeType !== 1 ) ;
171+ } while ( cur && cur . nodeType !== 1 ) ; // ELEMENT_NODE(1)
159172
160173 return cur ;
161174}
162-
175+ // 由于要定义方法的参数列表几乎一样,这里使用了一个小技巧,简洁地批定义一堆方法
163176jQuery . each ( {
164177 parent : function ( elem ) {
165178 var parent = elem . parentNode ;
@@ -168,7 +181,7 @@ jQuery.each({
168181 parents : function ( elem ) {
169182 return jQuery . dir ( elem , "parentNode" ) ;
170183 } ,
171- parentsUntil : function ( elem , i , until ) {
184+ parentsUntil : function ( elem , i , until ) { // i应当是后续调用map时传入的index,但是目前并没有用
172185 return jQuery . dir ( elem , "parentNode" , until ) ;
173186 } ,
174187 next : function ( elem ) {
@@ -204,17 +217,29 @@ jQuery.each({
204217 jQuery . fn [ name ] = function ( until , selector ) {
205218 var ret = jQuery . map ( this , fn , until ) ;
206219
207- if ( ! runtil . test ( name ) ) {
208- selector = until ;
209- }
210-
211- if ( selector && typeof selector === "string" ) {
220+ // 若方法名不是以 Until 结尾, 则 ……
221+ // 实去除以下三个方法,他们拥有相同的参数列表:parentsUntil、 prevUntil、 nextUntil
222+ if ( ! runtil . test ( name ) ) {
223+ selector = until ;
224+ }
225+
226+ /*
227+ * 根据API文档,只有三个以 Until 结尾的方法接受第二个参数
228+ * 并且 selector 是用来过滤(filter)用的,
229+ * 所以有下面这个if判断,且执行该逻辑
230+ */
231+ if ( selector && typeof selector === "string" ) {
212232 ret = jQuery . filter ( selector , ret ) ;
213233 }
214234
215- ret = this . length > 1 && ! guaranteedUnique [ name ] ? jQuery . unique ( ret ) : ret ;
235+ // 参考模块开头处,guaranteedUnique[ name ] 为 true 的可能性只有name为 children、contents、next、prev时
236+ // 所以满足条件的方法名有:parent, parents, parentsUntil, nextAll, prevAll, nextUntil, prevUntil, siblings
237+ // $.unique 将DOM元素数组中重复的元素移除
238+ ret = this . length > 1 && ! guaranteedUnique [ name ] ? jQuery . unique ( ret ) : ret ;
216239
217- if ( this . length > 1 && rparentsprev . test ( name ) ) {
240+ // 匹配 parents, parentsUntil, prevUntil, prevAll
241+ // 为了结果元素符合正常情况,便于使用,会对结果集进行一个倒排
242+ if ( this . length > 1 && rparentsprev . test ( name ) ) {
218243 ret = ret . reverse ( ) ;
219244 }
220245
@@ -223,6 +248,13 @@ jQuery.each({
223248} ) ;
224249
225250jQuery . extend ( {
251+ /**
252+ * @desc
253+ * @param expr
254+ * @param elems
255+ * @param not
256+ * @return {Array }
257+ */
226258 filter : function ( expr , elems , not ) {
227259 if ( not ) {
228260 expr = ":not(" + expr + ")" ;
@@ -232,20 +264,42 @@ jQuery.extend({
232264 jQuery . find . matchesSelector ( elems [ 0 ] , expr ) ? [ elems [ 0 ] ] : [ ] :
233265 jQuery . find . matches ( expr , elems ) ;
234266 } ,
235-
236- dir : function ( elem , dir , until ) {
267+ /**
268+ * @desc 从一个元素出发(不包括出发点元素),获取迭代搜索方向上的所有元素,直到遇到document对象或遇到until匹配的元素停止
269+ * @param {Element } elem 起始元素
270+ * @param {string } dir 迭代搜索方向,可选值:'parentNode', 'nextSibling'、 'previousSibling'
271+ * @param {string } until 选择器表达式,如果遇到 until 匹配的元素,迭代终止
272+ * @return {Array }
273+ */
274+ dir : function ( elem , dir , until ) { // 一个简单的 dir 参数,使得函数支持遍历祖先、兄长、兄弟
237275 var matched = [ ] ,
238- cur = elem [ dir ] ;
239-
276+ cur = elem [ dir ] ; // 跳过 elem 自身
277+ /**
278+ * 迭代条件(简化):cur.nodeType !== 9 && !jQuery( cur ).is( until )
279+ * 迭代访问,直到遇到document对象或遇到until匹配的元素
280+ * cur.nodeType !== 9 当前DOM节点cur不是document对象
281+ * !jQuery( cur ).is( until ) 当前DOM节点cur不匹配表达式until
282+ *
283+ * until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )
284+ * 这个布尔表达式也有点意思,执行最后的jQuery.is的隐含条件是:until !== undefined && cur.nodeType === 1
285+ * 复合的布尔表达式和三元表达式,能减少代码行数、稍微提升性能,但是代码晦涩,不易阅读和维护。
286+ * 也许看不懂也是jQuery风靡的原因之一
287+ */
288+ // DOCUMENT_NODE(9)
240289 while ( cur && cur . nodeType !== 9 && ( until === undefined || cur . nodeType !== 1 || ! jQuery ( cur ) . is ( until ) ) ) {
241- if ( cur . nodeType === 1 ) {
242- matched . push ( cur ) ;
243- }
244- cur = cur [ dir ] ;
245- }
290+ if ( cur . nodeType === 1 ) {
291+ matched . push ( cur ) ;
292+ }
293+ cur = cur [ dir ] ;
294+ }
246295 return matched ;
247296 } ,
248-
297+ /*
298+ * @desc 简单来说,该方法获取元素 n 的所有后续兄弟元素,包含 n,但不包含elem
299+ * @param n {Element} 开始计算的元素
300+ * @param elem {Element} 跳过的元素
301+ * @return {Array } 从 n 开始直到结束的所有的兄弟元素,如果设置了elem,则不包括 elem
302+ */
249303 sibling : function ( n , elem ) {
250304 var r = [ ] ;
251305
@@ -260,6 +314,8 @@ jQuery.extend({
260314} ) ;
261315
262316// Implement the identical functionality for filter and not
317+ // 实现与 filter 和 not 同等的功能
318+ // keep 是一个布尔值
263319function winnow ( elements , qualifier , keep ) {
264320
265321 // Can't pass null or undefined to indexOf in Firefox 4
0 commit comments