A Low-down, Dirty Goblin Of A Hack
07 NOV
This is a dirty trick, it’s so dirty that I feel bad and wrong for even mentioning it but JavaScript just makes me do these things. It’s not my fault….I’m not in control here. You know when you are trying to work with the arguments array but you realise that it’s not really an array so it doesn’t have all those good methods like slice(), concat() etc. Well, there’s a way around that but it’s not pretty.
You see, JavaScript methods aren’t in anyway tightly bound to their object like in many other languages. If you like a method that a another object has you can just steal it. In the case above, we like that slice() method that arrays have, let’s just steal it:
[].slice.call(arguments, 1);
Ha! We created an empty array just to steal it’s slice() method then use call() to point this at the arguments array! And you know what? It works rather nicely on quite a lot of objects and methods. Go on, have a play…
15 Comments (Closed)
Now I feel sick.
sil at 07.11.06 / 11AM
When using Prototype.js you can simply
$A(arguments)
.
Mislav at 07.11.06 / 11AM
I feel dirty just reading it…;-)
Luke Redpath at 07.11.06 / 11AM
Actually it works on all array-like objects, say:
[].slice.call({0: ‘foo’, 1: ‘bar’, length: 2}, 1) // ‘bar’
I tested this in the JavaScript engine from Mozilla, what other engines support this?
Mark Wubben at 07.11.06 / 12PM
Awesome!
Bramus! at 07.11.06 / 12PM
Mislav: Yeah, good point. I forgot to mention that actually. In most cases cloning a whole array just to use one method is a bit of an overkill though. That’s why I keep the goblin handy :)
Dan at 07.11.06 / 12PM
Mark: It’s pretty stable in my experience. I’ve had a quick test and it seems to work in:
- IE 6/7
- Firefox 1.5 / 2
- Opera 9
- Safari 2.03 and Webkit
Dan at 07.11.06 / 13PM
Instead of creating a new array object just to throw it away later, you can directly access Array.prototype:
Array.prototype.slice.call(arguments, 1);
More verbose, but it feels a little less dirty.
Simon Willison at 07.11.06 / 13PM
Or….you could do a similar thing but in a more grimy way by just using the slice() method of any random array that’s in the scope….Wa ha ha!
It’s a shame that all the array methods don’t have a generic version like Array.forEach() in JS 1.6. Then we wouldn’t need to resort to all this evil stuff.
Dan at 07.11.06 / 13PM
This is the logical conclusion to the preceding comments:if (!Array.slice) { // mozilla already supports this Array.slice = function(object) { var slice = Array.prototype.slice; return slice.apply(object, slice.call(arguments, 1)); }; }Now you can do this:Array.slice(arguments, 1);
Dean Edwards at 07.11.06 / 15PM
Thattud do it!
Dan at 07.11.06 / 16PM
Dean stole my comment.
The natural extension of this idea is to provide
Array
generics for allEnumerable
methods andArray
builtins. It’d come in handy for arguments and node lists.
Andrew Dupont at 07.11.06 / 19PM
I suppose you can use a swiss method to take care of it as well.
Function.prototype.swiss = function(house) { for ( var i = 1; i < arguments.length; ++i ) { var thief = arguments[i]; this[thief] = house[thief]; } return this; };
Then it can easily be applied in this case
var fn = function() { }; fn.swiss(Array.prototype, 'map');
You’ve now stolen ‘map’ from Array:
fn.map(f);
Dustin Diaz at 07.11.06 / 22PM
Ah, this is so evil, I love it.
It opens up a whole world of using internal JS functions for totally new purposes. And I bet we could figure out some amazing hacks. What else is there to abuse?
Yes, I have a dirty mind.
Jesse Skinner at 08.11.06 / 05AM
That’s sweet.
Dr Nic at 17.11.06 / 10AM
About This Article
- Posted on: 07.11.06 / 10AM
- Categories: JavaScript
- Tags: hack, javascript, nasty
- Tweet