0

I often need to convert the result of a selector to an array of JQuery objects so that I can for..of on them, I end up doing a lot of:

const arr = $.makeArray($(selector)).map(el => $(el));

(I usually have a function doing this internally)

I then do things like:

for (let jel of arr) jel.toggle(false);

Does JQuery have a better/builtin way to create such arr ?

9
  • get. There's bound to be a previous question on this, I'll see if I can find one. Commented Sep 9, 2022 at 21:53
  • You can use Array.from(collection) or [...collection] as the generic way to convert an array-like object to a real array. But why do you need to use for-of when jQuery has a built-in $(selector).each(...)? Commented Sep 9, 2022 at 21:55
  • the point is to convert back to a result array where each item is not a dom object but a JQuery object Commented Sep 9, 2022 at 21:57
  • @kofifus - Sorry, misunderstood that. I'm curious what the use case is...? Vs. just using $() on what you get in the for-of? Commented Sep 9, 2022 at 22:00
  • 2
    hmm... I'm confused. Why aren't you just using $(selector).toggle(false)? feel like i'm missing something, since noone's mentioned this yet. There's rarely ever a need to actually have an array of individual jquery collections. jquery methods already implicitly work on each element individually. Commented Sep 9, 2022 at 22:05

1 Answer 1

3

As Kevin points out, in that specific case, there's no reason for the loop. toggle operates on the entire collection, so simply $("selector").toggle(false) (or $("selector").hide();). This is one of the great things about jQuery, it's set-based (for setters and actions; not for getters).

But if the goal is to get an array of individual jQuery wrappers around every element in a jQuery object, your version seems fine, but it can be slightly simpler:

const arr = Array.from($(selector), el => $(el));

That uses the mapping callback on Array.from, avoiding an unnecessary intermediate array:

const wrappers = Array.from($(".a"), (el) => $(el));
for (const wrapper of wrappers) {
    console.log(wrapper.text());
}
<div class="a">1</div>
<div class="a">2</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

If the goal is just to get an iterable (rather than an array) that can be used with for-of and anything else that understands iterables, wrapping each individual element in a jQuery wrapper, you could add a function (plugin) to do that using a generator function:

// The plugin
(($) => {
    jQuery.fn.wrapped = function*() {
        for (let n = 0; n < this.length; ++n) {
            yield $(this[n]);
        }
    };
})(jQuery);

// Using it
for (const wrapper of $(".a").wrapped()) {
    console.log(wrapper.text());
}
<div class="a">1</div>
<div class="a">2</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Or as a static method inspired by your comment below:

// The plugin
(($) => {
    $.iterable = function*(...args) {
        const wrapper = $(...args);
        for (let n = 0; n < wrapper.length; ++n) {
            yield $(wrapper[n]);
        }
    };
})(jQuery);

// Using it
for (const wrapper of $.iterable(".a")) {
    console.log(wrapper.text());
}
<div class="a">1</div>
<div class="a">2</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Sign up to request clarification or add additional context in comments.

2 Comments

oh cool I didn't know Array.from can do this ! glad I asked
instead of you plugin I added: JQuery.from = function (selector) { return Array.from($(selector), el => $(el)); } I can then for .. of $.from('.class')

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.