53
(() => console.log(arguments))(1,2,3);

// Chrome, FF, Node give "1,2,3"
// Babel gives "arguments is not defined" from parent scope

According to Babel (and from what I can tell initial TC39 recommendations), that is "invalid" as arrow functions should be using their parent scope for arguments. The only info I've been able to find that contradicts this is a single comment saying this was rejected by TC39, but I can't find anything to back this up.

Just looking for official docs here.

Dharman
  • 30,962
  • 25
  • 85
  • 135

2 Answers2

55

Chrome, FF, and node seem to be wrong here, Babel is correct:

Arrow functions do not have an own arguments binding in their scope; no arguments object is created when calling them.

looking for official docs here

Arrow function expressions evaluate to functions that have their [[ThisMode]] set to lexical, and when such are called the declaration instantiation does not create an arguments object. There is even a specifc note (18 a) stating that "Arrow functions never have an arguments objects.".

Pointy
  • 405,095
  • 59
  • 585
  • 614
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
54

As noted by Bergi, arrow functions do not have their own arguments variable.

However, if you do want to capture the args for your arrow function, you can simply use a rest parameter

const myFunc = (...args) =>
  console.log ("arguments", args)
  
myFunc (1, 2, 3)
// arguments [1, 2, 3]

Rest parameters can be combined with other positional parameters, but must always be included as the last parameter

const myFunc = (a, b, c, ...rest) =>
  console.log (a, b, c, rest)

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

If you make the mistake of writing a rest parameter in any other position, you will get an Error

const myFunc = (...rest, a, b, c) =>
  console.log (a, b, c, rest)
  
myFunc (1, 2, 3, 4, 5, 6, 7)
// Error: Rest parameter must be last formal parameter
Mulan
  • 129,518
  • 31
  • 228
  • 259
  • Yeah, but the transpiled version of that is a for loop over the arguments; significantly more code added –  Jun 22 '15 at 08:05
  • 2
    `/me shrugs` - I guess I don't really care about the transpiled output in most cases. There's more code added sure, but it's not like it doesn't work. If you care about transpiled output, you probably shouldn't be using a transpiler in the first place. I mean, just look at the transpiled output for a generator or destructuring assignment... – Mulan Jun 22 '15 at 08:21
  • 3
    The point is ES6 affords you a much more succinct/expressive/readable *source* code. The build code output should not matter too much so long as it still performs to your expectations. – Mulan Jun 22 '15 at 08:21
  • `Yeah but... who cares ?` -- I do, at least for what I'm working on right now. In general, I agree, but the needless `for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; }` is too heavy for my current project when I'm doing things like writing function language helpers (`map = (...args) => flip(args)`). Having that extra code 20 times is far too much. It's not an issue of it expanding into more source than the original, it's an issue of it expanding into _significantly_ more source than I could write myself (your 2nd ex is good) –  Jun 22 '15 at 10:33
  • 3
    But this whole thing is off-topic for this question anyway ;) –  Jun 22 '15 at 10:35
  • Javascript does have a *new* (since version 1?) keyword that does exactly that: `function`: `const log = function(){console.log.apply(console,arguments);}` :) – Rick Love Dec 02 '17 at 14:31