当前位置: 代码迷 >> Web前端 >> jQuery源码历代记五
  详细解决方案

jQuery源码历代记五

热度:100   发布时间:2012-10-24 14:15:58.0
jQuery源码历代记5

?

之前文章传送门:http://adamed.iteye.com/category/207898

?

下面要介绍的jQuery构造器中的方法是入栈、出栈方法:

?他们分别是pushStack和end。

先看下putStack的API描述

.pushStack( elements )

elements? An array of elements to push onto the stack and make into a new jQuery object.?

?

?

Description: Add a collection of DOM elements onto the jQuery stack.
?

?

之前我们一直说jQuery集合是一个类似于数组的数据结构,那么它是如何构成的呢?我们看下pushStack的源码:

?

?

pushStack : function( a , args ) {
    var fn = args && args[args.length - 1];
    if ( !fn || fn.constructor != Function ) {
        if ( !this.stack ) this.stack = [];
        this.stack.push( this.get() );
        this.get( a );
    } else {
        var old = this.get();
        this.get( a );
        if ( fn.constructor == Function ) return this.each( fn );
        this.get( old );
    }
    return this;
}
?

?

?

这里有一个小问题点在于逻辑与运算符的返回值。

由于&&既不改变运算元的数据类型,也不强制运算结果的数据类型。所以我们测试:

var a = "abc"&&"bcd";

alert(a);

我们看到弹出框返回的值为"bcd",当然如果将表达式前面的"abc"换成null则最后也会返回值null。

综上args && args[args.length - 1];返回值为:若args为null则返回null否则返回args的最后一个元素,并将结果付给变量fn。

下面的代码判断若fn不存在或者fn不为function则执行以下逻辑(修改jQuery这个数组对象内容):

1、判断当前jQuery对象中是否包含变量stack若不包含则新建一个数组给它。

2、将当前对象放置如数组中。

3、将a放入数组中。

这里出现第2个小问题:?this.stack.push( this.get() );??????this.get( a ); 这2句是做什么的?

第1句是执行this.get()并将结果放入stack数组中,而第2句this.get(a)只是执行,并没有对返回结果做任何操作。有什么作用呢?

请大家注意.pushStack( elements ) 中elements 的定义是? An array of elements

所以this.get(a)将执行的代码是:

?

?

?

get : function( num ) {
    if ( num && num.constructor == Array ) {
        this.length = 0;
        [ ].push.apply( this , num );
        return this;
    }
}
?

?

?

?

其结果是将当前jQuery结果集清空并将a放入其中。

所以this.stack.push( this.get() );??????this.get( a );这2句的意思就是将原来的结果集保存进this.stack将新结果集放入this。

那么下面那个else中的4句话:

var old = this.get();

this.get( a );

if ( fn.constructor == Function ) return this.each( fn );

this.get( old );

的意思就是说:

1、将老结果集保存进变量old。

2、将this指定为新结果集。

3、对新结果集每个元素上执行fn。

4、回复this为老结果集。

?

//**********************这是分隔符********************************上面只是从源码的角度逐句阐述了每条语句的意思,但是会有些知其然不知其所以然的感觉。

后面会在讲解用到pushStack方法的find方法时回头重新梳理一下执行过程帮助理解为什么要这样写。

?

//**********************这是分隔符********************************

下面介绍的是出栈方法end:

?

?

end : function() {
    return this.get( this.stack.pop() );
}
?

?


end方法可以很好说明pushStack方法中this.stack的作用:

.end()

?

?

 Description: End the most recent filtering operation in the current chain and return the set of matched elements to its previous state. 

?

举例说明一下:

HTML代码:

?

?

?

<p>text</p>
<p class="middle">Middle</p>
<p>text</p>
?

?

?

JS代码:

?

alert($('p').filter('middle').length);//alerts 1
alert($('p').filter('middle').end().length);//alerts 3
?

?

?很明显的证明end就是恢复由于过滤类方法(add、filter等)对结果集造成的影响。

//**********************这是分隔符********************************

下面就介绍会影响结果集的几个方法:find、clone、filter、not、add

?第一个介绍的是find,作用是查找结果集中各元素的子元素。

.find( selector )

selector A string containing a selector expression to match elements against.

?

?

?

Description: Get the descendants of each element in the current set of matched elements, filtered by a selector, jQuery object, or element.
?

距离说明:

HTML代码

?

<p>aaa<em>aaa</em></p>
<p>aaa<em>aaa</em></p>
<p>aaaaaa</p>
?

?

JS代码

?

 alert($("p").find('em').length);//alerts 2
?

?

?

?

?//**********************这是分隔符********************************

?

?

find : function( t ) {
    return this.pushStack( jQuery.map( this , function( a ) { return jQuery.find( t , a ); } ) , arguments);
}
?

?

我们结合上面的例子讲解代码:

其中使用了jQuery的map方法,该方法在jQuery源码历代记1中已经剖析过了,这里只是重复一下map的作用:

根据jQuery.map() 的API的描述,该方法的作用是:

Description: Translate all items in an array or object to new array of items.
?

?

jQuery.map( array, callback(elementOfArray, indexInArray) )

?

array? The Array to translate.

callback(elementOfArray, indexInArray)?? The function to process each item against. The first argument to the function is the array item, the second argument is the index in array The function can return any value. Within the function, this refers to the global (window) object.

//**********************这是分隔符********************************

jQuery.map( this , function( a ) { return jQuery.find( t , a ); }的含义是对于this中的每一个元素执行jQuery.find方法并将结果以数组形式返回。jQuery.find顾名思义就是在上下文a中查找t。(jQuery.find方法的源码非常的长,稍后专门剖析)所以这1句的含义就是遍历集合的每一个元素,将元素中匹配t的元素找出来整合成一个新的数组(下面用子结果集数组来表示这个结果数组)。

我们回顾上面的例子:?alert($("p").find('em').length);//alerts 2

$("p")的结果包含3个p元素,执行find('em')后:jQuery.map( this , function( a ) { return jQuery.find( t , a ); }

导致结果为:['<em>aaa</em>','<em>aaa</em>'](注意这里数组的内容不应该是字符串,此处写成字符串主要是帮助理解)

this.pushStack(['<em>aaa</em>','<em>aaa</em>'], arguments);的执行过程为:

?

pushStack : function( a , args ) {
    //这里a为数组:['<em>aaa</em>','<em>aaa</em>']
    //这里的args为:'em'
    var fn = args && args[args.length - 1];
    //这里的fn为'em'
    if ( !fn || fn.constructor != Function ) {
    //fn符合此判断
        if ( !this.stack ) this.stack = [ ];
        //将原结果集3个p元素存放至this.stack
        this.stack.push( this.get() );
        //将结果集更新为2个新em元素的内容
        this.get( a );
    }
}
?

//**********************这是分隔符********************************

我们下面用大量的篇幅阐述一下jQuery.find的源码~~?

?

未完待续~~~

?

1 楼 zhangwenzhuo 2012-04-02  
为什么this.get()会返回本身的呢?
2 楼 adamed 2012-04-05  
zhangwenzhuo 写道
为什么this.get()会返回本身的呢?


源码历代记1里最后说了
  相关解决方案