12

I wanted to have an optional boolean parameter to a function call:

function test() {
  if (typeof(arguments[0]) === 'boolean') {
    // do some stuff
  }
  // rest of function
}

I want the rest of the function to only see the arguments array without the optional boolean parameter. First thing I realized is the arguments array isn't an array! It seems to be a standard Object with properties of 0, 1, 2, etc. So I couldn't do:

function test() {
  if (typeof(arguments[0]) === 'boolean') {
    var optionalParameter = arguments.shift();

I get an error that shift() doesn't exist. So is there an easy way to remove an argument from the beginning of an arguments object?

at.
  • 50,922
  • 104
  • 292
  • 461

3 Answers3

28

arguments is not an array, it is an array like object. You can call the array function in arguments by accessing the Array.prototype and then invoke it by passing the argument as its execution context using .apply()

Try

var optionalParameter = Array.prototype.shift.apply(arguments);

Demo

function test() {
    var optionalParameter;
    if (typeof (arguments[0]) === 'boolean') {
        optionalParameter = Array.prototype.shift.apply(arguments);
    }
    console.log(optionalParameter, arguments)
}
test(1, 2, 3);
test(false, 1, 2, 3);

another version I've seen in some places is

var optionalParameter = [].shift.apply(arguments);

Demo

function test() {
    var optionalParameter;
    if (typeof (arguments[0]) === 'boolean') {
        optionalParameter = [].shift.apply(arguments);
    }
    console.log(optionalParameter, arguments)
}
test(1, 2, 3);
test(false, 1, 2, 3);
Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
Arun P Johny
  • 384,651
  • 66
  • 527
  • 531
  • 4
    Note that this will affect any named arguments as well, and has a particularly interesting effect on the last argument provided when it's accessed as a named argument. If you have `function foo(a, b, c)` and you call `foo(1, 2, 3)` and do the shift above, both `b` and `c` will end up being `3`. This may be what you want. Or not. – T.J. Crowder Nov 11 '13 at 10:23
  • Surprised this works! so `shift` not only returns back the first element, but converts the `Object` passed in to an `array` and then back into an `Object` with the first element removed? Exactly what I was looking for, but surprising... – at. Nov 11 '13 at 18:26
  • @at that's not actually what it does. The "shift" code runs and "pretends" that the object is really an array; it performs no conversion. It's for that reason that this trick has the effect noded by Mr. Crowder. If you need to do this sort of thing, you should probably just convert `arguments` to an array and work from there. – Pointy Nov 11 '13 at 18:53
  • 3
    If you want to leave `arguments` untouched and create a new array use slice: `var newArguments = [].slice.call(arguments, 1);` – Christiaan Westerbeek Jun 23 '15 at 12:36
  • What's important to understand is that in Javascript, functions are themselves objects and so can have a life on their own. You can take them from one object and put them onto another. Combine this with the fact that all array functions, by contract, only depend on the object having a `length` property and you can see why this solution works. – Stijn de Witt Sep 19 '15 at 20:13
2

As Arun pointed out arguments is not an array

You will have to convert in into an array

var optionalParameter = [].shift.apply(arguments);

Clyde Lobo
  • 9,126
  • 7
  • 34
  • 61
1

It's not fancy but the best solution to remove the first argument without side effect (without ending with an additional argument as would do shift) would probably be

  for (var i=0;i<arguments.length;i++) arguments[i]=arguments[i+1];

Example :

function f(a, b, c, d) {
  for (var i=0;i<arguments.length;i++) arguments[i]=arguments[i+1];
  console.log(a,b,c,d); 
}
f(1,2,3,4); // logs 2,3,4,undefined
Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
  • 1
    After your code runs, `arguments.length === 4`. I think you should finish the job by setting it to `arguments.length-1` after the for loop. – Stijn de Witt Sep 19 '15 at 20:24