jQuery的prevObject

概述

遇到一个关于jQuery的end()方法的问题,我猜jQuery保存了一开始选中的对象,结果查阅源码才知道,jQuery保存了一个prevObject的属性,维护了一个jQuery的对象栈。

详解

先来看end()方法的实现

1
2
3
4
5
//...
end: function() {
return this.prevObject || this.constructor();
}
//...

这里我们看到有一个prevObject,这个this.prevObject到底是用来干什么的呢?没错,jQuery通过这个属性维护了一个jQuery对象栈,只要我们使用选择相关的方法(如find(),eq()等)获取新的jQuery对象,jQuery就会把之前的对象存储在prevObject中。

先来看看eq方法的源码。

1
2
3
4
5
6
7
//...
eq: function(i) {
var len = this.length,
j = +i + (i < 0 ? len : 0);
return this.pushStack(j >= 0 && j < len ? [this[j]] : []);
}
//...

可以看到eq()方法中返回的其实是pushStack()方法的返回值,而交给pushStack方法的参数其实是就是我们需要获取的当前jQuery对象第i个元素,注意这里的参数还是DOM对象。

接下来我们来看pushStack方法中的实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//...
pushStack: function(elems) {
var ret = jQuery.merge(this.constructor(), elems);
ret.prevObject = this;
return ret;
}
//...
merge: function(first, second) {
var len = +second.length,
j = 0,
i = first.length;
for(; j < len; j++) {
first[i++] = second[j];
}
first.length = i;
return first;
}

jQuery.merge()方法就是将第2个参数中的各个参数拼接到第1个参数的尾部,这里我们看到,第一个参数this.constructor(),其实是创建了一个空的jQuery对象。

于是我们得到了我们所需要的jQuery对象,然后我们将当前对象赋值给新对象的prevObject属性,最后返回新对象,这样,新对象就持有了一个对之前对象的引用,这样就实现了一个维护前一个jQuery对象的栈。

总结

jQuery的prevObject就是通过pushStack的方式来实现保存对象栈的。

参考

  1. jQuery.end() - jQuery API Document