循环遍历集合中的jQuery对象,而不为每次迭代初始化一个新的jQuery对象

Looping through jQuery objects in a collection without initializing a new jQuery object for each iteration

本文关键字:对象 jQuery 初始化 迭代 一个 集合 遍历 循环      更新时间:2023-09-26

我发现自己总是这样做:

$myElements.each( function(index, currentHtmltmlElement) {
  var $currentJqueryElement = $(currentHtmltmlElement);
  // Working with $currentJqueryElement
});

在每次迭代中初始化一个新的jQuery对象是一个巨大的性能损失。

所以我想这样做(credit也去decx@freenode):

for (var index = 0; index < $myElements.length; index++) {
  var $currentJqueryElement = $myElements.eq(i);
  // Working with $currentJqueryElement
}

但是我修复了一个JSPerf测试,结果证明这个代码片段的性能与第一个代码片段的性能相同!(

都太慢了!对于非常大的集合,您甚至可以注意到页面冻结。

所以我想知道在集合中迭代jQuery对象的快速方法是什么。

该方法也应尽可能方便使用。:

$items.each$item( function( $item, index ) { /* Working with $item directly. */ });

远远优于古代for (var i=0...的无能。

乌利希期刊指南2014-05-27

这里有一个例子。假设你有很多jQuery UI滑块:

<div class="my-slider"></div>
<div class="my-slider"></div>
<div class="my-slider"></div>
$sliders = $('.my-slider').slider();

现在您想要记录以控制每个滑块的值。你必须这样做:

$sliders.each( function(index, htmlSlider) {
  $current_slider = $(htmlSlider); // This step is a huge performance penalty
  console.log(
    $current_slider.slider('value')
  );
});

所以任务是摆脱性能损失。

您不能简单地执行$sliders.slider('value'),因为这将只输出集合中第一个滑块的值。

你不能在循环中恢复到普通的JS,因为你不能在没有jQuery对象的情况下访问jQuery小部件。

到目前为止,所有这些方法…

  • $sliders.each( function(index, htmlSlider) { htmlSlider });
  • $sliders.each( function() { this });
  • for (var i = 0; i < $sliders.length; i++) { $sliders.eq(i); }
  • $.each$.makeArray$.map

…使用$sliders的底层HTML元素数组,并且需要一个耗时的$( )初始化来访问jQuery特性。

Try

$.each($p, function(i, v) {
  test = $(v)
})

for + eq() : 702

each() : 722

this : 718

$.each() : 757 ("fastest")

http://jsperf.com/jquery-for-eq-vs-each/5

编辑

你不能直接把jQuery集合分成几个部分,你只能用单独的HTML元素创建新的集合。-洛莫斯-安德烈Mikhaylov

Try (at console, this page)

$("div"); // jQuery `collection` ? approx. `222` members, changes
// `split` 1st `101` members of jquery `obj`, or `collection` 
var split_jq_obj_1 = $("div").slice(0, 111); 
// `split` 2nd `101` members of jquery `obj`, or `collection` 
var split_jq_obj_2 = $("div").slice(-111); 
// Note `prevObject` and `selector` properties of  `jQuery` `object`
// `split_jq_obj_1` and `split_jq_obj_2` 
// `prevObject: e.fn.e.init[222]` , `selector: "div.slice(0,111)"`, 
// `prevObject: e.fn.e.init[222]`, `selector: "div.slice(-111)"`) 

// check results 
console.log($("div"), split_jq_obj_1, split_jq_obj_2);         
console.log($("div").length, split_jq_obj_1.length, split_jq_obj_2.length);

其他可能的方法

// `jquery` `object`, or `objects` 
var arr = $.makeArray($.map($("div"), function(value, index) {
  return ( index < 111 ? [$(value)] : null )
}), $.map($("div"), function(value, index) {
  return ( index >= 111 ? [$(value)] : null )
}));
console.log(arr); // `collection` of `jQuery` `objects`
// iterate `jquery` object`, or `objects`, 
// find `length` of `class` `item-content`
$.each($(arr), function(index, value) {
  console.log($(value).find(".item-content").length) // `29` (see `iteration` at `console`)
});
// check results
$(".item-content").length; // `29`
编辑2014-05-28

Try this (pattern)

$(function () {
    var sliders = $('.sliiider').slider({
        min: 0,
        max: 100
    });
    $('html').click(function () {
        $.when(sliders)
            .then(function (data) {
            for (var i = 0; i < data.length; i++) {
                // `$()` jQuery `wrapper` _not_ utilized,
                // not certain about quantifying `cost`, if any,
                // of utilizing jquery's `deferred` `object`s
                // test by sliding several `sliders`,
                // then `click` `document`, or `html`
                console.log(data.eq(i).slider("value"))
            };
        })
    });
});

jsfiddle http://jsfiddle.net/guest271314/8gVee/

fwiw,这个模式似乎也可以工作,没有使用jquery的init包装器$()

$(function () {
    var sliders = $('.sliiider').slider({
        min: 0,
        max: 100
    });
    $('html').click(function () {
        $.when(sliders)
            .then(function (data) {
            // Note, 2nd parameter to `.each()` not utilized, here
            data.each(function (i) {  
                // `$()` jQuery `init` `wrapper` _not_ utilized, 
                // within `.each()` `loop`,
                // same result as utilizing `for` loop,
                // "performance", or "fastest" not tested as yet
                console.log(data.eq(i).slider("value"));
            })
        });
    });
})

jsfiddle http://jsfiddle.net/guest271314/G944X/

只使用this关键字?似乎是最快的,更不用说(客观上)最容易理解。

$myElements.each( function() {
  var $currentJqueryElement = $(this);
});
http://jsperf.com/jquery-for-eq-vs-each/3

如果性能是一个问题,为什么不跳过jQuery和使用纯JS?

更新的答案

如果您想获得滑动条值(似乎只是css style "left"的数量),您可以这样做:

var elems = document.getElementsByClassName('my-slider');
for (var i = 0; i < elems.length; i++){
    console.log(elems[i].style.left); // logs : xx.xx%
}

会更快吗?也许吧。该方法适合所有用例吗?很可能不会,但对于特定的问题,它应该有效。

如果您证明我错了,我会很高兴,但我得出的结论是, jQuery集合是一个统一的对象,不能通过进行迭代,只有它所代表的HTML元素被存储为可以枚举的单独实体。你不能直接把jQuery集合分成几个部分,你只能用单独的HTML元素创建新的集合。

因此,只要有可能,就在循环中恢复原生JS特性,以提高性能。