数字营销 · Web开发 · 基础设施

jQuery中pushStack的原理和应用

本文简单分析jQuery中pushStack的实现原理,了解它如何创建新的jQuery对象、保存prevObject,以及与end()方法共同实现链式操作。

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 保存合并后的对象,然后给这个对象保存 prevObjectcontext 属性,最后返回这个新的 ret 对象。

这里有几点需要注意:

  1. this.constructor指向当前jQuery对象的构造函数,因此this.constructor()可以创建一个新的jQuery对象。
  2. jQuery.merge()是把传入的元素集合合并到新的jQuery对象中,所以ret本身仍然是一个jQuery对象。这也解释了为什么传入普通DOM对象之后,仍然可以继续使用css()等jQuery实例方法。
  3. 返回对象的prevObject属性保存了当前对象的引用,因此可以通过这个属性找到上一个jQuery对象,end()方法正是利用这一机制返回上一层对象。

简单来说,pushStack的核心作用就是: 创建一个新的jQuery对象保存当前操作结果,同时把之前的jQuery对象保存到 prevObject 中,从而实现jQuery的链式查找和 end() 返回机制。

评论0

欢迎分享你的看法,也欢迎补充不同的实践经验。