Thanks to atk and jdalton for making the solution more robust and compliant! :)
-
-
Save eliperelman/1031656 to your computer and use it in GitHub Desktop.
[].filter || (Array.prototype.filter = // Use the native array filter method, if available. | |
function(a, //a function to test each value of the array against. Truthy values will be put into the new array and falsy values will be excluded from the new array | |
b, // placeholder | |
c, // placeholder | |
d, // placeholder | |
e // placeholder | |
) { | |
c = this; // cache the array | |
d = []; // array to hold the new values which match the expression | |
for (e in c) // for each value in the array, | |
~~e + '' == e && e >= 0 && // coerce the array position and if valid, | |
a.call(b, c[e], +e, c) && // pass the current value into the expression and if truthy, | |
d.push(c[e]); // add it to the new array | |
return d // give back the new array | |
}) |
[].filter||(Array.prototype.filter=function(a,b,c,d,e){c=this;d=[];for(e in c)~~e+''==e&&e>=0&&a.call(b,c[e],+e,c)&&d.push(c[e]);return d}) |
DO WHAT THE **** YOU WANT TO PUBLIC LICENSE | |
Version 2, December 2004 | |
Copyright (C) 2011 Eli Perelman http://eliperelman.com | |
Everyone is permitted to copy and distribute verbatim or modified | |
copies of this license document, and changing it is allowed as long | |
as the name is changed. | |
DO WHAT THE **** YOU WANT TO PUBLIC LICENSE | |
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | |
0. You just DO WHAT THE **** YOU WANT TO. |
{ | |
"name": "arrayFilter140Polyfill", | |
"description": "A tweet-sized polyfill for Array.prototype.filter", | |
"keywords": [ | |
"array", | |
"filter", | |
"polyfill", | |
"prototype" | |
] | |
} |
<!DOCTYPE html> | |
<title>Array filter polyfill</title> | |
<div>Expected value: filter the array values outside of our range (less than 6)</div> | |
<script> | |
[].filter||(Array.prototype.filter=function(a,b,c,d,e){c=this;d=[];for(e in c)~~e+''==e&&e>=0&&a.call(b,c[e],+e,c)&&d.push(c[e]);return d}); | |
var arr = [1,2,3,4,5,6,7,8,9,10]; | |
// creates new array of [1,2,3,4,5] and reassigns it to arr. | |
arr = arr.filter(function(value) { | |
return value < 6; | |
}); | |
</script> |
The line containing
a.call(b, c[e], e, c) &&
should be
a.call(b, c[e], +e, c) &&
So the index passed to the callback is a number and not a string.
Also devs should keep in mind that the order in which for..in
iterates over properties is not spec'ed.
So for example this fallback may produce:
var a = [];
a[2] = 'c';
a[1] = 'b';
a[0] = 'a';
var b = a.filter(function(v) { return v; });
b; // ['c', 'b', 'a'];
[].filter||(Array.prototype.filter=function(f,c,d){d=[];this.forEach(function(v,k,s){f.call(c,v,k,s)&&d.push(v)});return d})
125 bytes :P
@bga that defeats the purpose of this needing to be an ES5 polyfill.
@eliperelman heh but you have Array#forEach polyfill too :)
Agreed, but then this script wouldn't be able to operate on its own.
I just don't understand what the difference between [].filter
and Array.prototype.filter
is.
If you set [].filter, you set the filter method of an anonymous Array, but if you change Array.prototype.filter, you set the filter method of all Arrays. Still, [].filter is shorter, but allows to check if a (native) filter method is present.
So why don't just use Array.prototype.filter
?
If we overwrite an existing native class, we risk negative effects e.g. in Chrome. So we rather stick with this safe method.
Isn't Array.prototype.filter || (Array.prototype.filter = ...)
doing the same?
Yes, but longer than [].filter||(Array.prototype.filter=...)
That is the point.
Why is there [].filter||(Array.prototype.filter||function()...
?
Compared to what alternative?
Why is there [].filter||(Array.prototype.filter||function()...?
It's a typo. It should be:
[].filter||(Array.prototype.filter=function()...
@jdalton Are you saying this wouldn't work:
Array.prototype.filter = [].filter || (function()...
@ jdalton Are you saying this wouldn't work:
Array.prototype.filter = [].filter || (function()...
Chrome has a bug where Array.prototype.filter = [].filter
will cause Array#filter
to become enumerable.
Also there's still a typo in the test.html snippet.
This
Array.prototype.filter=[].filter||(Array.prototype.filter=
should be this
[].filter||(Array.prototype.filter=...)
Ah, I see. We don't even want to execute the polyfill if the method exists. No reassignment.
Save 2 bytes.
[].filter||(Array.prototype.filter=function(a,b,c,d,e){d=[];for(e in c=this)~~e+''==e&&e>=0&&a.call(b,c[e],+e,c)&&d.push(c[e]);return d})
Is there a reason why you do ~~e+''==e
and e>=0
? From what I know both do (almost) the same, checking if e
is a number (to be more precise, the first checks for an int, the second for a double). I think it's shorter to use a plain for loop. The following version is 133 bytes and works in IE7 and IE8.
[].filter||(Array.prototype.filter=function(a,b,c,d,e){c=this;d=[];for(e=0;e<c.length;e++)a.call(b,c[e],e,c)&&d.push(c[e]);return d})
This also fixes a problem we came across in our getElementsByClassName. In IE7 and IE8 the for-in loop does not return numeric indices for elements with an ID. It returns the IDs instead for these elements. If you do (for example) document.getElementsByTagName('*')
on a document where all elements contain an ID, all these elements will be skipped. Forcing e
to be a number solves this problem.
@maettig the ~~e+''==e and e>=0
is to ensure the key is a number and it's not negative.
Your version skips the in
check for sparse arrays. You really shouldn't be using these snippets in production code.
e>=0
is enough to check for non-negative numbers. Is it really necessary to check for decimal places? I forgot about sparse arrays. But as said, using for-in is broken in IE on NodeList's.
e>=0 is enough to check for non-negative numbers. Is it really necessary to check for decimal places?
the ~~e+''==e
also guards against keys like 08
too.
I forgot about sparse arrays. But as said, using for-in is broken in IE on NodeList's.
There is only so many characters allowed. As I have said before code-golf is not appropriate for production code so please don't look for it to be a robust and to-the-letter solution. As it is, the currently solution meets mark for a workable approximation of Array#filter
. The important part is we have at least brought up/made aware the issues with each variation.
Updated from the comments. Thanks guys!