Arguments Object in JavaScript

MDN defines arguments as an array-like object corresponding to arguments passed to a function. This is provided to functions through an implicit local variable called arguments by JavaScript. The arguments object provides an array-like interface to actual arguments. Being array-like, each argument in the argument object, is indexed starting from zero, and has a length property that tells you how many arguments were passed to the function.

I should note here that the arguments object does not have any other Array properties except length.

Even though it’s an array-like object, you can still extract some of Array’s methods and use the Function.prototype.call method on the arguments object to call them. Let me demonstrate:

function showArguments () {
if (arguments.length > 0) {
var first_arg = Array.prototype.shift.call(arguments);
console.log(first_arg);
}
}

This is a contrived example, but I just wanted to show how you can use Array methods on an arguments object. Here, I set the arguments object as explicit receiver of the shift method and assigned the result of that call(first argument passed to the function if any) to the variable first_arg which is then outputted to the console.

What I wanted to really talk about regarding the arguments object is a little quirk that you may or may not have come across.

Assume you have a code like this:

function example (a, b) {
Array.prototype.shift.call(arguments);
Array.prototype.shift.call(arguments);
console.log(a); // => 'Three'
console.log(b); // => 'Four'
}
example(1,2,3,4);

I’ve removed the first and second arguments by calling Array.prototype.shift twice on arguments, and if you’re like me, you’re probably expecting the output for a and b to be 1 and 2 respectively. Well, that’s not the output you get. Let me go ahead and attempt to explain why this happens.

The arguments object is not a copy of the function’s arguments. Rather, the named arguments are aliased to their corresponding indices in the arguments object. So, that means a and b are aliased to arguments[0] and arguments[1] respectively. And even after I removed a(first) and b(second) from the arguments object with Array.prototype.shift, the third and fourth arguments — which are now the first and second in the arguments object — passed to the function during invocation are still aliased to a and b.

The simple illustration below, hopefully, will help clarify this behavior.

function example (a,b) {};

The named parameters a & b are mapped to their corresponding indices

(a         ,       b)
 |                  |
| |
arguments[0]       arguments[1]

Invoke example and pass in 4 arguments.

Note: JavaScript functions are variadic

example(1,2,3,4)

Each argument is mapped to it’s corresponding index.

(  1  ,        2   ,           3  ,         4)
| | | |
arguments[0] [arguments[1] arguments[2] arguments[3]

Invoke Array.prototype.shift.call(arguments) twice. This will remove the arguments 1 & 2 passed into the example function. This means arguments.length will now equal 2, and the 3rd and 4th arguments passed to the function will now occupy the arguments[0] and arguments[1] positions respectively.

Array.prototype.shift.call(arguments);
Array.prototype.shift.call(arguments);

Here is the tricky part: the named parameters a & b are still aliases of arguments[0] and arguments[1] respectively.

  (3)         (4)       
| |
arguments[0] [arguments[1]
| |
(a) (b)

The parameters a and b are still aliases of arguments[0] and arguments[1]. hence the output is: 3 and 4.

The important thing to keep in mind here is how altering the arguments object can affect named parameters. If you must alter the arguments object, convert it into an Array and save it to a variable.

function example (a,b) {
  var arg_arr = Array.prototype.slice.call(arguments);
// do something with arg_arr
}

Another twist: ES5’s strict mode disallows modifying arguments object. Let’s demonstrate that real quick.

function example1 (x) {
'use strict';
arguments[0] = 'modified';
return x === 'modified'; // => false
}

function example2 (x) {
arguments[0] = 'modified';
return x === 'modified'; // => true
}

I’m still looking at new features introduced in ES6 for dealing with arguments and parameters, and hopefully that will be the subject of my next post.

Show your support

Clapping shows how much you appreciated Obi Anaedozie’s story.