Skip to content

Commit 2fd4cc5

Browse files
author
swaydeng
committed
read someting ,next is winnow
1 parent 346959a commit 2fd4cc5

1 file changed

Lines changed: 78 additions & 22 deletions

File tree

traversing.js

Lines changed: 78 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ var runtil = /Until$/,
1010
prev: true
1111
};
1212

13+
// 为 jQuery 实例对象提供扩展方法:
14+
// find, has, not, filter, is, closest, index, add, addBack
1315
jQuery.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 文档里的区别是:前者不接受参数,后者可选接受一个查找参数
147153
jQuery.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)
151159
function 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+
*/
155168
function 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+
// 由于要定义方法的参数列表几乎一样,这里使用了一个小技巧,简洁地批定义一堆方法
163176
jQuery.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

225250
jQuery.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 是一个布尔值
263319
function winnow( elements, qualifier, keep ) {
264320

265321
// Can't pass null or undefined to indexOf in Firefox 4

0 commit comments

Comments
 (0)