Way back in March 2009, I wrote a quick post about the JavaScript arguments quasi-array, about how the interpreter sets it up on every call to every function to hold the arguments passed to that function.
Although I blithely talked about the fact that arguments
was array-like, it wasn’t a real array (it’s not typeof Array
) and didn’t have methods like pop()
and the like. In fact, it only really has a length
property and a bunch of properties named ‘0’, ‘1’, ‘2’ and so on. So it’s easy to iterate over the elements, er, properties, but that’s essentially it.
It’s actually quite easy to convert it to an array and then use that. You don’t even have to use the obvious for
loop to do it either. You use the Array’s prototype’s slice()
method:
var argsArray = Array.prototype.slice.call(arguments);
Since arguments
does not have the slice()
method, we have to use the call()
function to call it on arguments
(this is an application of the apply invocation). slice()
returns part of an array as an array, but If you don’t pass any arguments to it – start index, end index – the function returns all of the elements instead. Which is, if you think about it, what we want.
So, if you have, say, a logging library for your code, and you want to log the values of the arguments to a particular function, you could do something like this:
var convertArgs = function (args) { return Array.prototype.slice.call(args); }; var myLoggingLibrary = { logArguments: function (argsArray) { console.log(argsArray); } }; var someFunctionToTest = function (a, b, c, d) { // do something with the arguments; we’ll just print the first console.log(a); }; var addArgumentsLogging = function (f) { return function () { var args = convertArgs(arguments); myLoggingLibrary.logArguments(args); f.apply(this, args); }; }; someFunctionToTest(1, 2, 3, false); // prints "1" someFunctionToTest = addArgumentsLogging(someFunctionToTest); someFunctionToTest(1, 2, 3, false); // prints "[1, 2, 3, false]" then "1"
With the addArgumentsLogging()
function, I am not altering the function to be logged: I am merely creating a wrapper around it that does the logging and then calls the original function using the apply invocation. Notice how I’ve replaced the original function with the wrapped version. (Note also that the addArgumentsLogging
function creates a closure over the parameter f
.)
So there you go: how to convert the arguments quasi-array into a real array and then use it.
Now playing:
Groove Armada - Little By Little
(from Goodbye Country (Hello Nightclub))
2 Responses
#1 Ju said...
07-Jan-12 1:26 AMYou can also use '[].slice.call(arguments,0);' which saves some typing :)
#2 julian m bucknall said...
07-Jan-12 7:27 AMJu: Cool :) If a smidgeon obfuscated...
Cheers, Julian
Leave a response
Note: some MarkDown is allowed, but HTML is not. Expand to show what's available.
_emphasis_
**strong**
[text](url)
`IEnumerable`
* an item
1. an item
> Now is the time...
Preview of response