3

I have a collection of elements, and whilst each has a unique String identifier, I can't safely use it's value as the elements ID as I can't guarantee that it'll only contain valid characters. As a result, I'm storing the identifiers in each of the elements jQuery .data() object. Whilst I could use a data- attribute, I don't really like the idea of using selectors where I may have to escape quotes etc., but if there's a huge efficiency bonus, it should be taken into consideration. A solution using the .data() object would be also be great as this could be applicable for any data type.

I'm wondering what the most efficient way to select a single element would be. At present, this is my solution:

function get_group($from, group) {
  var $result = $();
  $from.each(function() {
    if($(this).data("group") == group) {
      result = $(this);
      return false;
    }
  });
  return $result;
}

I iterate over each of my results until I find a match. When I do, I break from the loop. By initializing $result as an empty jQuery object, I'll always return jQuery, which I think is most consistent with standard practice and in particular the .filter() method.

I think this is better than using .filter() with a function as it explicitly returns a single (or no) item, and stops iteration as soon as it needs to, but is there a better approach?

Community
  • 1
  • 1
Ian Clark
  • 9,237
  • 4
  • 32
  • 49

3 Answers3

1

It would seem that a for loop is faster than the one you've got:

function get_group ($from, group)
    for (var i = 0; i < $from.length; i++) {
        if ($($from[i]).data("group") == group) {
            return $($from[i]);
        }
    }
    return $();
}

JSPerf: http://jsperf.com/each-vs-data-selector

EDIT: Rewrote to function, added return $()

Nicklas Nygren
  • 2,595
  • 13
  • 19
  • Thanks, but I'm not using a HTML5 `data-` attribute, I'm using a jQuery `data()` object's attribute. However, looking at your tests, that seems like a pretty nice solution - do you really need to wrap the `$from[i]` in jQuery though? Also, you'd need to return `$()` if you completed the loop unsuccessfully. – Ian Clark Aug 06 '13 at 12:15
  • Yeah, I know you're not. I added the tests because some of the answers suggest that that would be the fastest solution. As for wrapping `$from[i]` in jQuery, that is necessary, because `$from[i]` is not a jQuery object. I've added an example using `.eq(i)` instead, but that one's slower. – Nicklas Nygren Aug 06 '13 at 12:38
  • 1
    This was the best answer, sorry for taking so long to give it recognition. – Ian Clark Aug 22 '13 at 14:44
0

As you said , if each data-group is unique, you can do this -

$('[data-group="'+group+'"]')
Adil Shaikh
  • 44,509
  • 17
  • 89
  • 111
  • I don't like this approach as appending an unknown string into a jQuery selector doesn't seem sensible (not least because of quote issues) – Ian Clark Aug 06 '13 at 11:23
0
$from.find('[data-group="' + group + '"]')
Samuel
  • 2,106
  • 1
  • 17
  • 27
  • I don't like this approach as appending an unknown string into a jQuery selector doesn't seem sensible (not least because of quote issues) – Ian Clark Aug 06 '13 at 12:03
  • Agreed, but this approach makes code compact and readable and jQuery has a failsafe mechanism that returns an empty array if the selector matches nothing. Problems will arise if the given sting corrupts the JS syntax. I guess the decision will depend on whether the actual text is supplied by a program (fairly safe) or a user (potentially unsafe). – Samuel Aug 06 '13 at 12:12
  • Although elegant, it's almost 60% slower than making a simple for loop. – Nicklas Nygren Aug 06 '13 at 12:50
  • Performance vs code clarity trade-off. But question was 'Optimize' so +1 for Nicklas ;) – Samuel Aug 06 '13 at 13:33