为什么用.each()遍历jQuery对象时,不能得到jQuery对象?

为什么用.each()遍历jQuery对象时,不能得到jQuery对象?,jquery,Jquery,以下工作如预期: $(".foo").first().text("hi!") …因为返回一个jQuery对象 但是,如果我想使用所有匹配的方法,我需要执行以下操作: $(".foo").each( function(idx, obj) { $(obj).text("hi!") } ) …因为它为您提供了DOM对象 这种令人困惑的差异背后的设计原因是什么?如何避免为每个匹配构建jQuery对象?您看到vs 您应该能够执行以下操作: $('li').each(function(index

以下工作如预期:

$(".foo").first().text("hi!")
…因为返回一个jQuery对象

但是,如果我想使用所有匹配的方法,我需要执行以下操作:

$(".foo").each( function(idx, obj) {
  $(obj).text("hi!")
  }
)
…因为它为您提供了DOM对象

这种令人困惑的差异背后的设计原因是什么?如何避免为每个匹配构建jQuery对象?

您看到vs

您应该能够执行以下操作:

$('li').each(function(index) {
    alert(index + ': ' + $(this).text());
});
按第一个链接。试试
$(this)
而不是
$(obj)

试试

$(".foo").each( function(idx, obj) {
  $(this).text("hi!")
  }
)

可能是由于与在大型集合上循环相关的性能原因?如果只需要DOM对象,则可以保存循环。如果您需要jQuery对象,那么您可以很容易地获得它


我通常不向每个方法提供第二个参数,因此我可以使用$(this)。

我认为,由于jQuery使用包装器对象,第一个方法使用原始包装器,并且只删除包装器中除第一个元素以外的所有元素,因此保持它为jQuery对象


但是,如果它们为
each()
函数的每个节点提供jQuery对象,那么它们将产生为每个节点创建包装的开销。而且,由于您不一定需要该包装器对象,因此它将产生不必要的开销。

jQuery在内部为
$(“sel”).each(function(){})

eq
是一个简单的片段:

eq: function( i ) {
    return i === -1 ?
    this.slice( i ) :
    this.slice( i, +i + 1 );
}
因此,您可以创建一个新的
函数来代替
对象[name]
来执行
对象:eq(i)

因此,要创建自己的
每个

$.fn.each2 = function(callback)
{
   for ( var i = 0; i < this.length; ++i ) {
      callback.call( this.eq(i), i, this.eq(i) )
   }
};

$("*").each2(function(i, obj) {
    alert(obj); // now obj is a jQuery object
});

每次迭代都会受到明显的性能影响。在每次迭代中创建一个新的jQuery对象会慢得多,而且在大型集合中可能会很明显。通常,您不需要包装对象的额外便利性,尤其是在访问单个属性或属性时。您经常会看到循环浪费代码,如
$(this).is(“:checked”)
而不是
this.checked


除此之外,我想说,这是因为它有道理。jQuery对象通常表示DOM对象的集合,这些对象的大小可以是任意数量。有时候,jQuery纯粹是为了支持选择器和事件绑定而使用的,仅此而已。当迭代一个包含更多元素的集合时,返回一个包含单个元素的集合没有多大意义。更合理的做法是返回一个更可能需要的项目,即DOM元素,然后如果需要添加的功能,可以使用jQuery对其进行包装。这也使它与迭代NodeList和其他类型的集合保持一致。

可能是因为,在您的示例中,甚至没有理由使用
每种类型的集合。而不是:

$(".foo").each( function(idx, obj) {
  $(obj).text("hi!");
)
只需使用:

$(".foo").text("hi!");

在处理jQuery集时,所有内容都自动使用复数。

正是我要说的,另外,如果first()没有返回jQuery对象,则必须使用$($(选择器).first()),这与jQuery简洁的目标有些冲突。好吧,我的印象是,
$(“.foo”)
首先创建jQuery对象,当通过
each()
时,它们被剥离为“基本”DOM对象。我想这不完全是怎么回事:)@Jon-那不正确
$(选择器).first()返回jQuery对象。您不应该再次使用
$($(选择器).first())
包装它。据我所知,唯一返回普通DOM元素的jQuery方法是
.get(0)
,当您向它传递一个数字时。如果没有number参数,您将得到一个DOM元素数组。@patrick dw:我是在说明如果first()不返回jQuery对象,您将要做什么,并说明为什么first()返回jQuery对象是有意义的。这与其他方法没有任何意义上的区别。我仍然需要创建jQuery对象。
$()
构造函数仍然存在。因此也可以工作吗?:)我现在还需要做一些分析,以了解哪个更快。@badp:是的。我认为在
obj[I]
obj.slice(I,I+1)
上没有太大区别。。。请参见此处的示例@BrunoLM,实际上
$(“.foo”)[i]
返回一个DOM对象,而
$(“.foo”).eq(i)
给出一个jQuery对象。这里的要点非常重要,考虑到通过切片实现
eq
,我几乎相信
$($(“.foo”)[I])
会更快……事实上,将BrunoLM的each2实现改为只调用
eq(I)
执行时间大约减半一次--.@BrunoLM:您确定列表中始终包含jQuery对象吗?如果是这样的话,那就引出了最初的问题:为什么jQuery一开始就不这样实现呢?我需要每次点击调用一个函数,这比只调用
.text()
call:)要复杂得多,但这正好解决了问题——如果需要为集合中的每个项执行一些独特的操作,将它们与“.foo”一起选择是否有意义?是的,如果我想对每个“.foo”中的值应用一个数学函数。相同的函数,不同的输入,不同的输出。啊,在这种情况下,我建议将函数传递到text(),但另一张海报可能已经建议了。我在想你可能在做一些像
$(this).text($(this).hasClass(“selected”)?“selected”:“)
或者一些愚蠢的事情,在这种情况下,我建议你只做jQuery(.foo.selected”)或者其他什么。
$.fn.each2 = function(callback)
{
   for ( var i = 0; i < this.length; ++i ) {
       var jObj = this.eq(i);
      callback.call( jObj, i, jObj )
   }
};

$.fn.each3 = function(callback)
{
   for ( var i = 0; i < this.length; ++i ) {
       var jObj = $(this[i]);
      callback.call( jObj, i, jObj )
   }
};
$(".foo").each( function(idx, obj) {
  $(obj).text("hi!");
)
$(".foo").text("hi!");