pushStack是jQuery内核中一个非常重要的函数,它的重要性在于,许多jQuery内部函数都会频繁用到它。平常开发中虽然很少直接使用pushStack,但理解这个函数不仅有利于理解jQuery的运行原理,也有助于理解jQuery对象之间的链式操作。
顾名思义,pushStack有“入栈”的意思。栈作为一种数据结构,是一种只能在一端进行插入和删除操作的特殊线性表。数据入栈时,类似我们进电梯,后进先出,如下图:

jQuery中的“栈”其实并不是真正意义上的栈,而是给新的jQuery对象附加一个属性,用来指向当前对象的上一个对象。通过 end() 方法,就可以返回上一个对象。例如:
<span>1</span>
<span>2</span>
<span>3</span>
<script>
$('span').eq(0).css('fontSize','20px').end().fadeOut(2000);
</script>
上面的代码会先选择第一个 span ,将字体大小设置为20px,然后通过 end() 返回之前的 $('span') 对象,最后让所有span在2秒钟内 fadeOut 。
pushStack属于jQuery的实例方法,可以通过jQuery对象调用。例如:
$().pushStack(document.getElementsByTagName('div'))
.css('background','blue');这段代码可以把所有div的背景设置为蓝色。那么pushStack的原理是什么?为什么传入的普通DOM元素集合,经过pushStack之后也可以使用 css() 等jQuery方法呢?
先来看一下jQuery中pushStack的源码:
pushStack: function( elems ) {
// Build a new jQuery matched element set
var ret = jQuery.merge( this.constructor(), elems );
// Add the old object onto the stack (as a reference)
ret.prevObject = this;
ret.context = this.context;
// Return the newly-formed element set
return ret;
}
// jQuery.merge
merge: function( first, second ) {
var l = second.length,
i = first.length,
j = 0;
if ( typeof l === "number" ) {
for ( ; j < l; j++ ) {
first[ i++ ] = second[ j ];
}
} else {
while ( second[j] !== undefined ) {
first[ i++ ] = second[ j++ ];
}
}
first.length = i;
return first;
}pushStack的实现其实比较简单,主要涉及到jQuery的静态方法 merge 。这个方法的作用是合并两个类似数组的对象,设计思路是在第一个对象的基础上,把第二个对象中的元素依次附加进去。
再回到pushStack函数,首先定义一个局部变量 ret 保存合并后的对象,然后给这个对象保存 prevObject 和 context 属性,最后返回这个新的 ret 对象。
这里有几点需要注意:
this.constructor指向当前jQuery对象的构造函数,因此this.constructor()可以创建一个新的jQuery对象。jQuery.merge()是把传入的元素集合合并到新的jQuery对象中,所以ret本身仍然是一个jQuery对象。这也解释了为什么传入普通DOM对象之后,仍然可以继续使用css()等jQuery实例方法。- 返回对象的
prevObject属性保存了当前对象的引用,因此可以通过这个属性找到上一个jQuery对象,end()方法正是利用这一机制返回上一层对象。
简单来说,pushStack的核心作用就是: 创建一个新的jQuery对象保存当前操作结果,同时把之前的jQuery对象保存到 prevObject 中,从而实现jQuery的链式查找和 end() 返回机制。
评论0
欢迎分享你的看法,也欢迎补充不同的实践经验。