2010-10-16 112 views
13

預期以下工作:爲什麼用.each()迭代jQuery對象不給我jQuery對象?

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

...因爲first()返回一個jQuery對象。

但是,如果我想對所有比賽的text()方法來工作,我需要做的:

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

...因爲each()給你D​​OM對象。

這個令人困惑的區別背後的設計原因是什麼?我該如何避免爲每個匹配構建一個jQuery對象?

回答

11

可能由於涉及到遍歷大集合性能方面的原因?如果您只需要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

0

你看到.each VS jQuery.each

你應該能夠做到以下幾點:

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

%的第一個鏈接。嘗試$(this)代替$(obj)

+0

這是沒有意義的方式不同。我仍然需要製作jQuery對象。 – badp 2010-10-16 15:28:15

0

嘗試

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

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

0

我相信,由於jQuery使用包裝對象,第一個方法使用原始包裝,並只刪除包裝中的第一個元素,從而保持它爲jQuery對象。

但是,如果他們爲每個節點提供了一個jQuery對象,那麼它們會產生爲每個節點創建包裝的開銷。由於你不一定需要這個包裝器對象,它會產生不必要的開銷。

1

內部的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

1

有明顯的性能損失,這將是採取每次迭代。每次迭代創建一個新的jQuery對象比較大的集合要慢得多並且可能很明顯。通常,您不需要包裝對象的附加便利,特別是在訪問單個屬性或屬性時。您經常會看到像$(this).is(":checked")這樣的週期浪費代碼,而不是this.checked

除此之外,我會說這是因爲它有意義。一個jQuery對象通常代表可以是任何數量的DOM對象的集合。有時候,jQuery純粹用於選擇器支持和事件綁定,並沒有太多。迭代包含單個元素的集合時,迭代多個元素的集合時沒有多大意義。返回更可能需要的單個項目(DOM元素)會更有意義,如果您需要添加的功能,則可以使用jQuery來包裝它。這也保持了對NodeList和其他類型集合的迭代。

0

可能是因爲在你的例子中沒有理由甚至使用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