84

All you know that arguments is a special object that holds all the arguments passed to the function.

And as long as it is not an array - you cannot use something like arguments.slice(1).

So the question - how to slice everything but first element from arguments?

UPD:

seems like there is no way without converting it to an array with

var args = Array.prototype.slice.call(arguments);

If someone posts another solution it would be great, if not - I'll check the first one with the line above as an answer.

zerkms
  • 249,484
  • 69
  • 436
  • 539
  • +zerkms there is indeed a better way than taking `arguments` and converting it to an array etc. Please see my answer below. – Umur Karagöz Nov 24 '17 at 09:43

9 Answers9

140

Q. How to slice everything but first element from arguments?

The following will return an array containing all arguments except the first:

var slicedArgs = Array.prototype.slice.call(arguments, 1);

You don't have to convert arguments to an array first, do it all in one step.

nnnnnn
  • 147,572
  • 30
  • 200
  • 241
  • I believe there is a downside with this. If there is only one additional argument (besides the first one) nothing is returned. – Trevor Jan 06 '14 at 22:20
  • @Trevor - No, it returns an array with one element that is the second argument. (Why would it return nothing?) – nnnnnn Jan 07 '14 at 05:01
  • Yep, my bad. A different bug of mine was causing this. – Trevor Jan 08 '14 at 20:23
  • 4
    Recommendation [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments) states that you should not use slice on arguments because it prevents JavaScript engine optimizations. – Jonathan Lin May 08 '15 at 05:25
  • 1
    a more in detail explanation can be found [here](https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#3-managing-arguments) – David Chase Aug 01 '15 at 04:19
  • ^ doesn't explain anything and simply states it leaks. – Nijikokun Oct 08 '15 at 22:21
  • 1
    Seems that recommendation not to use slice on arguments is no longer there. The "more in detail" link does not seem to have any more relevant details. Seems like this is definitely the correct answer now. – David Jan 28 '16 at 02:36
  • 4
    @David - The "in detail" link still says not to use `.slice()` on `arguments`, but the only reason given is that it prevents JS engine optimisation of the function. So it's not that it fails, it just *might* be slower. I'm not going to write code to cater to optimisation in the JS engine of the day, not when the engine of tomorrow might have solved the optimisation problem, and in any case the difference probably won't be perceptible to the user in most cases. Better to write clear and easy-to-maintain code first, then come back and optimise only if a measurable performance issue arises. – nnnnnn Jan 28 '16 at 05:27
  • Yeah, sure, I meant that it does not give any extra information other than "it leaks" - no explanation how or why. It seems like it would be okay to me, the only proviso is that it might not get optimised... I'm with you though, I'd not worry about that, and it seems like MDN agrees, having removed the advice not to do it. – David Jan 29 '16 at 04:57
27

Meddling with array functions is not actually necessary.

Using rest parameter syntax ...rest is cleaner and more convenient.

Example

function argumentTest(first, ...rest) {
  console.log("First arg:" + first);

  // loop through the rest of the parameters
  for (let arg of rest) {
    console.log("- " + arg);
  }
}

// call your function with any number of arguments
argumentTest("first arg", "#2", "more arguments", "this is not an argument but a contradiction");

...Rest

Mohammad Faisal
  • 2,144
  • 15
  • 26
Umur Karagöz
  • 2,970
  • 1
  • 19
  • 29
12

From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments:

You should not slice on arguments because it prevents optimizations in JavaScript engines (V8 for example). Instead, try constructing a new array by iterating through the arguments object.

So Paul Rosiana's answer above is correct

bluescrubbie
  • 530
  • 4
  • 11
  • 4
    Maybe so. But I don't see how optimization engines couldn't treat the accepted answer's one-liner and optimize it in any way they wish. It's always a nuisance in the long run if we start to code for the optimizers (of the day) - personally I prefer clarity of code. – akauppi May 11 '15 at 07:47
  • 2
    'slice' does not alter. It returns a shallow copy of elements from the original array. Elements of the original array are copied into the returned array. So I cannot understand what is difference between manual copy to new array and slice. – Maxim Jul 17 '15 at 21:40
  • 1
    As of 2018, the warning is not there anymore. We should be safe, I guess. – GBF_Gabriel Dec 13 '18 at 23:09
12

This can be a way:

var args = Array.from(arguments).slice(1);
Di Tran
  • 193
  • 1
  • 2
  • 8
  • These days it's not necessary at all: `function foo(...args)` – zerkms Aug 23 '17 at 07:24
  • @zerkms I was about to dismiss your suggestion for performance reasons, but my test is showing rest parameters as the fastest solution! https://gist.github.com/18d590d12aef1e90d2ed262f4fab0c96 – Cody Allan Taylor Aug 29 '17 at 04:47
  • @CodyAllanTaylor implementations improve. Unless you have a really-really-really important reason to not to, I would stick to the more readable syntax – zerkms Aug 29 '17 at 05:12
11

You can "slice without slicing" by procedurally walking the arguments object:

function fun() {
  var args = [];

  for (var i = 1; i < arguments.length; i++) {
    args.push(arguments[i]);
  }

  return args;
}

fun(1, 2, 3, 4, 5); //=> [2, 3, 4, 5]
Paul Rosania
  • 9,823
  • 2
  • 20
  • 18
0

You can use the method [].slice.call(arguments, 1)

[].slice will return you the slice function object and you can call it as the arguments and 1 are the parameters

Thierryk
  • 1
  • 1
  • Any change you checked through the posted answers before posting yours? The identical (and even slightly better, since it does not allocate a throw-away array) answer is already posted and is checked. – zerkms Dec 01 '17 at 20:29
0

You can use ...rest within the function to separate the first and the rest of the arguments:

function foo(arr) {
  const [first, ...rest] = arguments;
  console.log(`first = ${first}`);
  console.log(`rest = ${rest}`);
}
//Then calling the function with 3 arguments:
foo(1,2,3)
ntarlapan
  • 381
  • 2
  • 3
0

you can use this too

function arg(myArr) {
  let arg = Object.values(arguments).slice(2, 4);
  console.log(arg);
  return arg;
};

arg([1, 2, 3], 4, [5,6], 7)

see here for reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values

...

0

Arguments type is iterable, so using the ES6 (ES2015) spread ... operator, then use Array.slice([start], [end]) method, such as

function omitFirstAndLastArgument(value) {
  const args = arguments.length > 2 ? [...arguments].slice(1, -1) : [];
  return args;
}

omitFirstAndLastArgument(1, 2, 3, 4, 5, 6); //  [2, 3, 4, 5]
AamirR
  • 11,672
  • 4
  • 59
  • 73