Reputation: 5611
While trying to write some awesome JS I ran into some strange JS-behaviour. I've created a piece of code to demonstrate my problem:
<html>
<head>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
var images = $('.images').children();
var filtered = images.filter(function(i, image) {
console.log(this);
}, "abc");
});
</script>
</head>
<body>
<div class="options">
<div class="filters">
</div>
<ol class="pagination">
</ol>
</div>
<div class="results">
<ul class="images">
<li data-category="Zakelijk">Result 1</li>
<li data-category="Speels">Result 2</li>
<li data-category="Blogging">Result 3</li>
<li data-category="Zakelijk">Result 4</li>
<li data-category="Speels">Result 5</li>
<li data-category="Blogging">Result 6</li>
<li data-category="Zakelijk">Result 7</li>
<li data-category="Speels">Result 8</li>
<li data-category="Blogging">Result 9</li>
<li data-category="Zakelijk">Result 10</li>
<li data-category="Speels">Result 11</li>
<li data-category="Blogging">Result 12</li>
<li data-category="Zakelijk">Result 13</li>
<li data-category="Speels">Result 14</li>
<li data-category="Blogging">Result 15</li>
</ul>
</div>
</body>
</html>
Ok, now my question. When using the Array.filter method you pass in a callback function as first parameter and an optional context as second parameter. As you can see, I'm passing "abc" as context (which is ridiculous, ofcourse). I would expect my console to throw a lot of "abc", but instead it prints the jQuery elements!
Can someone shine some light on this please?
Thanks,
Martijn
Upvotes: 2
Views: 1949
Reputation: 1074168
As you can see, I'm passing "abc" as context (which is ridiculous, ofcourse). I would expect my console to throw a lot of "abc", but instead it prints the jQuery elements!
You're using jQuery's filter
, which doesn't have a context parameter, rather than ES5's Array#filter
, because you're calling filter
on a jQuery object, and jQuery objects are not arrays (although they offer a lot of array-like functionality, and several "methods" with similar names — including filter
).
Three options for you:
makeArray
You can use jQuery's makeArray
to turn the jQuery object into an array, e.g.:
$(function() {
var images = $.makeArray($('.images').children());
var filtered = images.filter(function(i, image) {
console.log(this);
}, "abc");
});
proxy
/ bind
Or alternately, you can use jQuery's proxy
function (or ES5's Function#bind
) to bind the iterator function you're passing to jQuery's filter
so it ignores the this
jQuery supplies:
$(function() {
var images = $('.images').children();
var filtered = images.filter($.proxy(function(i, image) {
console.log(this);
}, "abc"));
});
Array#filter
to the jQuery objectOr you can apply Array#filter
directly to the jQuery object:
$(function() {
var images = $('.images').children();
var filtered = Array.prototype.filter.call(images, function(i, image) {
console.log(this);
}, "abc");
});
...since Array#filter
is expressly defined to work on anything array-like, not just Array
s. That last might actually be the most efficient way to do it. Fiddle
Upvotes: 6