Going inside the new jQuery.map()

For those that are curious and a little more advanced, there are some neat things going on under the hood of the new jQuery.map() that I would like to talk about.

Adding object support seems pretty trivial at first since jQuery.each() is already doing it - so it must be an easy patch, right? Well, not really. Let's look at how jQuery.each() is doing it. If you look at the jQuery source on github, you'll see that it's doing:

Can you see the flaw in this? It's going to treat the variable object (could be an array or object) like an object if length is undefined. What happens when I have an object with a "length" property? It dies a horrible death. Some have reported this issue.

For the new jQuery.map(), we wanted support for objects and also be able to pass an object with a length property and not have it blow up like jQuery.each() does. Dan Heberden came to the rescue. Dan spent some time making sure that jQuery.map() didn't face the same fate while keeping performance in mind.

We're checking to see if elems is an instanceof jQuery. We're doing this first because you're most likely dealing with a jQuery collection/array-like object. Since jQuery collections are treated like regular arrays (uses for loop), this is an optimized way of checking if we should treat elems like an array. Below is an example of jQuery.fn.map() in action.

7 comments

@kuindji: That is a known issue. Something that's being pondered over due to the fact that it adding additional logic would affect performance. It's a balancing act between performance and making sure the most common use-case is covered - which we're assuming it won't be common for people to pass length: 0 as an object.

Hi
Even if you can achieve the same result with jQuery.each(), but having alternatives for doing something is not that bad. Though, consistency may decrease and developers may loose time learning that new things are not increasing their programming power, and just provide additional ways to do the same thing.

@Saeed Neamati: I believe the reason to add object support to $.map was not just to provide "an additional way to do the same thing". It was due to the fact that passing an object to $.map was a behavior that most expected would work.