0
\$\begingroup\$

I have the following code which iterates through some divs of an array to show() them. I was wondering if there is any way to rewrite the for loop using filter(). Will this have a better performance over my initial code?

var selectEnabledGenerators = function(generators) {
    //List of generator indexes to show
    var list = generators;
    var allGenerators = $(".generatorContainer");
    //Hide all generators
    allGenerators.hide();
    //maybe use filter here?
    for (var i = 0, max = list.length; i < max; i++) {
        $(".generatorContainer[data-generator=" + list[i] + "]").show();
    }
};
\$\endgroup\$
  • 1
    \$\begingroup\$ As explained in this answer of mine, you can use join on array to create a comma-separated selector and avoid for loop completely. You can use '.generatorContainer[data-generator="' + list.join('"], .generatorContainer[data-generator="') \$\endgroup\$ – Tushar Dec 28 '16 at 2:54
  • \$\begingroup\$ Using any of the array iterators will not give you a performance boost, quite the opposite in fact. The for or while loops are the quickest way iterate over any array. To further improve performance use the DOM API to query for elements rather than jQuery. \$\endgroup\$ – Blindman67 Dec 29 '16 at 12:48
1
\$\begingroup\$

I was wondering if there is any way to rewrite the for loop using filter().

What if I say you can avoid for loop completely.

Yes, you can avoid loop by letting jQuery do that for you. jQuery accepts multiple comma-separated selectors and internally iterate over each selector and perform operations.

generators is an array of elements, this array elements can be joined with , as glue, to create the selector.

Let's say, we have an array var selectors = ['#someId', '.myClass', 'tag'] and we want to add a class to all these selectors. We can iterate over the array and add the class to each element individually or we can combine the array elements somehow to create a comma-separated string and pass this to jQuery as selector.

$(selectors.join(', ')).addClass('magic');

selectors.join(', ') will join the array elements by ,, thus giving '#someId, .myClass, tag' which is valid selector and can be passed to jQuery and any method defined on jQuery prototype can be called on it.


Same logic can be used, in your case.

As join will add the glue between the elements of array, the prefix and suffix need to be concatenated.

The selector can be created using

'.generatorContainer[data-generator="'
    + list.join('"], .generatorContainer[data-generator="')
    + '"]'

Line #1 is the prefix

Line #2 will give firstElement"], .generatorContainer[data-generator="secondElement"], ..., .generatorContainer[data-generator="lastElement

Line #3 will add suffix to make the selector valid.

With this, the code will be

var selector = '.generatorContainer[data-generator="' + list.join('"], .generatorContainer[data-generator="') + '"]';
$(selector).doMagic(); // He He

To add to the complexity, not() can be used to exclude elements

$('.generatorContainer').not(selector).hide(); // Hide those except in array
$(selector).show();                            // Show only those in array
\$\endgroup\$
2
\$\begingroup\$
  • This is kinda pointless:

    var list = generators;
    

    The generators argument is already a local variable. I get you might want to call it by a different name, but in that case the parameter should be called generatorIndices or something more descriptive.

  • The allGenerators variable isn't necessary. It could be, but you're not reusing it. You could just write $(".generatorContainer").hide();.

And yes, you can use jQuery's filter. You've already found all .generatorContainer elements once, so that's the collection you want to filter.

I'd probably just do:

var selectEnabledGenerators = function (generatorIndices) {
    var containers = $(".generatorContainer").hide();
    generatorIndices.forEach(i => containers.filter(`[data-generator=${i}]`).show() );
};
\$\endgroup\$
  • 1
    \$\begingroup\$ I'll suggest to add the quotes in attribute-value selector to value. As the array elements value is not shown in the question, it's better to wrap the value in quotes when used in selector to avoid strange results when value contains spaces or special characters. You can use [data-generator="${i}"]. Also, this is ES6. If target environment does not support it, you can mention to use normal functions instead of arrow functions and string concatenation instead of template literals. \$\endgroup\$ – Tushar Dec 28 '16 at 4:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.