I'm just wondering if anyone knows why $.map
and $.fn.map
pass arguments in flipped order from one-another. Is there a valid reason (e.g. ECMA specs somewhere) for it or was it just a poorly-planned API that is 开发者_如何学运维now impossible to fix due to the amount of code relying on jQuery?
$.map([ 'a', 'b', 'c' ], function(){ console.log(arguments); })
// ['a', 0], ['b', 1], ['c', 2]
$.fn.map.call([ 'a', 'b', 'c' ], function(){ console.log(arguments); })
// [0, 'a'], [1, 'b'], [2, 'c']
.each
doesn't act like this
Indeed, that might be considered as an oversight, but there is a very good reason for the arguments to be passed in that order.
Of course, on the surface, that's because the map() / each() methods and $.map() are not supposed to be equivalent, and each side is meant to be used in its own way (dealing with jQuery objects and arrays/hashes, respectively).
But the main point is that the parameter position is optimized for the case your callback function only wants to take a single argument. Consider both cases:
map()
andeach()
are meant to be called on jQuery objects, and the callback function will be called in the context of each DOM element involved in the mapping/loop (the context object is available through thethis
keyword). So, it makes more sense to pass the index first, then the element, becausethis
already designates the element.$.map()
deals with arrays and Javascript objects (hashes), and the callback function is invoked in the "global" context (this
is always thewindow
object). So, it makes more sense to pass the value first, then the index, because mapping is about avoiding loop index variables in the first place. If the caller is interested in those, he can use a "standard"for
loop (or the second argument passed to the callback function).
Here's my completely and entirely speculative "answer".
jQuery.each()
, .each()
and jQuery.map()
were all present in version 1.
.map()
was added in 1.2.
My guess is that they simply didn't give consideration to having the each
methods follow the forEach
in the spec. (What was the status of ES 5 at that time anyway?) But for some reason they did follow closer to the spec for $.map()
. (Maybe its original intention was for primarily internal use as well.)
So when jQuery 1.2 came along, they decided it would be nice to have a .map()
method.
So the question they faced was to have .map()
follow $.each()
and .each()
, or follow $.map()
.
Since .each()
in particular had already been implemented as callable against a jQuery object, they felt that it would cause less confusion to have .map()
follow .each()
than to follow $.map()
, which is most certainly not used as much.
Looking at the source for the .map()
method vs the .each()
method, you can see that .map()
requires an intermediate function in order to flip around the arguments and set the this
value. Somehow I doubt that they would have wanted to do that if they had it all planned out in advance.
Again, this is complete and utter speculation, but I wouldn't be surprised if it happened something like that.
Take it or leave it. ;o)
Ok, I did some digging in the code and the API changelog.
$.fn.map
internally calls jQuery.map
.
Its a guess (somewhat calculated) but I believe it was done to add the ability to traverse objects/collections.
精彩评论