为什么用.each()迭代jQuery对象不给我jQuery对象?

为什么用.each()迭代jQuery对象不给我jQuery对象?

问题描述:

预期以下工作:为什么用.each()迭代jQuery对象不给我jQuery对象?

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

...因为first()返回一个jQuery对象。

但是,如果我想对所有比赛的text()方法来工作,我需要做的:

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

...因为each()给你D​​OM对象。

这个令人困惑的区别背后的设计原因是什么?我该如何避免为每个匹配构建一个jQuery对象?

可能由于涉及到遍历大集合性能方面的原因?如果您只需要DOM对象,则可以节省周期。如果你需要jQuery对象,那么你可以很容易地得到它。

我通常不会为每个参数提供第二个参数,所以我可以使用$(this)。

+0

正是我想说的,再加上如果first()没有返回一个jQuery对象,你将不得不使用$($(selector).first()),这与jQuery的简洁目标有些冲突。 – 2010-10-16 15:25:48

+0

好吧,我的印象是,$(“。foo”)让jQuery对象以_开头,当它们通过'each()'时,它们被分解为“基本”DOM对象。我想这不是什么在这里:) – badp 2010-10-16 15:34:41

+0

@Jon - 这是不正确的。 '$(selector).first()'* does *返回一个jQuery对象。你不应该用'$($(selector).first())'来包装它。当我们传递一个数字时,返回一个纯DOM元素的唯一jQuery方法是'.get(0)'。没有数字参数,你会得到一个DOM元素数组。 – user113716 2010-10-16 16:20:29

你看到.each VS jQuery.each

你应该能够做到以下几点:

$('li').each(function(index) { 
    alert(index + ': ' + $(this).text()); 
}); 

%的第一个链接。尝试$(this)代替$(obj)

+0

这是没有意义的方式不同。我仍然需要制作jQuery对象。 – badp 2010-10-16 15:28:15

尝试

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

'$()'构造函数仍然存在。 – badp 2010-10-16 15:29:13

我相信,由于jQuery使用包装对象,第一个方法使用原始包装,并只删除包装中的第一个元素,从而保持它为jQuery对象。

但是,如果他们为每个节点提供了一个jQuery对象,那么它们会产生为每个节点创建包装的开销。由于你不一定需要这个包装器对象,它会产生不必要的开销。

内部的jQuery调用此为$("sel").each(function(){});

if (isObj) { 
    for (name in object) { 
     if (callback.call(object[ name ], name, object[ name ]) === false) { 
      break; 
     } 
    } 
} 

而且eq是一个简单的切片:

eq: function(i) { 
    return i === -1 ? 
    this.slice(i) : 
    this.slice(i, +i + 1); 
} 

所以,你可以创建一个新的each函数,而不是object[name],会做一个object:eq(i)

$("*").slice(1,2).toSource() == $("*").eq(1).toSource(); 

所以要创建自己的each

$.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 
}); 

似乎each3快于each2http://www.jsfiddle.net/m7pKk/2/

$.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) 
    } 
}; 

See this example on jsFiddle with performance measurement.

+0

所以[this](http://gist.github.com/629941)也能工作吗? :)此外,我现在需要做一些分析,以了解哪一个更快。 – badp 2010-10-16 15:55:02

+0

@badp:是的。我认为'obj [i]'和'obj.slice(i,i + 1)'没有太大区别......参见这里的示例http://www.jsfiddle.net/m7pKk/ – BrunoLM 2010-10-16 16:02:55

+0

@ BrunoLM,实际上'$(“.foo”)[i]'返回一个DOM对象,而'$(“.foo”)。eq(i)'给出一个jQuery对象。这里的要点非常重要,并且通过切片实现'eq',我几乎相信'$($(“。foo”)[i])'会更快...... – badp 2010-10-16 16:07:46

有明显的性能损失,这将是采取每次迭代。每次迭代创建一个新的jQuery对象比较大的集合要慢得多并且可能很明显。通常,您不需要包装对象的附加便利,特别是在访问单个属性或属性时。您经常会看到像$(this).is(":checked")这样的周期浪费代码,而不是this.checked

除此之外,我会说这是因为它有意义。一个jQuery对象通常代表可以是任何数量的DOM对象的集合。有时候,jQuery纯粹用于选择器支持和事件绑定,并没有太多。迭代包含单个元素的集合时,迭代多个元素的集合时没有多大意义。返回更可能需要的单个项目(DOM元素)会更有意义,如果您需要添加的功能,则可以使用jQuery来包装它。这也保持了对NodeList和其他类型集合的迭代。

可能是因为在你的例子中没有理由甚至使用each。相反的:

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

只需使用:使用jQuery集时

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

一切都是自动复数。

+1

我需要为每个命中调用一个函数,这个函数比'.text()'调用更复杂:) – badp 2010-10-16 18:23:43

+0

但是,这正好解决了这个问题 - 如果你需要为集合中的每个项目做一些独特的事情,将它们全部与“.foo”一起选择是否有意义? – jpsimons 2010-10-16 19:03:14

+0

是的,如果我想对每个“.foo”中的值应用数学函数。功能相同,输入不同,输出不同。 – badp 2010-10-16 19:07:38