ES6 arrow functions and arguments

With the recent advancement in JavaScript, which is ES6 or ECMA Standard Level 6, there are few changes introduced to the JavaScript language and one of it is the Fat Arrow Functions. These are a more concise syntax for writing function expressions. They utilize a new token, =>, that looks like a fat arrow. Arrow functions are anonymous and change the way this binds in functions.

Contents

  1. What are fat arrow functions?
    1. Difference with the traditional functions?
    2. Specification?
  2. Users' Choice
  3. Problem
  4. Solution
  5. Summary

What are fat arrow functions?

Arrow functions make our code more concise, and simplify function scoping and the this keyword. They are one-line mini functions which work much like Lambdas in other languages like C# or Python. (See also lambdas in JavaScript). By using arrow functions, we avoid having to type the function keyword, return keyword (it’s implicit in arrow functions), and curly brackets.

Difference with the traditional functions?

We can see a great difference between the traditional functions that use the function keyword vs. the new ones. Let's consider the following code uses the traditional style.

var add = function (a, b) {  
  return (a + b);
};

Now the whole content of say about 50 characters is compressed into the new ones, which is just 25ish characters:

let add = (a, b) => (a + b);  

This is about 50% reduction in size, which is great, but thinking about the cleanliness it boasts, it has some dangers too:

  • How do you send the parameters here?
  • What about the context of this?
  • What about scoping inside the function?

Specification?

From the official ECMA 262 specification page, it has described in the Runtime Semantics: Evaluation:

ArrowFunction: ArrowParameters => ConciseBody

  1. If the function code for this ArrowFunction is strict mode code (10.2.1), let strict be true. Otherwise let strict be false.
  2. Let scope be the LexicalEnvironment of the running execution context.
  3. Let parameters be CoveredFormalsList of ArrowParameters.
  4. Let closure be FunctionCreate(Arrow, parameters, ConciseBody, scope, strict).
  5. Return closure.

An ArrowFunction does not define local bindings for arguments, super, this, or new.target. Any reference to arguments, super, this, or new.target within an ArrowFunction must resolve to a binding in a lexically enclosing environment. Typically this will be the Function Environment of an immediately enclosing function. Even though an ArrowFunction may contain references to super, the function object created in step 4 is not made into a method by performing MakeMethod. An ArrowFunction that references super is always contained within a non-ArrowFunction and the necessary state to implement super is accessible via the scope that is captured by the function object of the ArrowFunction.

Users' Choice

Arrow functions were introduced with ES6 as a new syntax for writing JavaScript functions. They save developers time and simplify function scope. Surveys show they’re the most popular ES6 feature:

Survey

Problem

The problem now is that there seems to be no way you can send any arguments to the functions defined this way. This means, at the prototype level, the arguments is not defined in the function.

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

On Google Chrome, when the above is executed on Developer Tools JavaScript Console, we get this.

Console

That's what the recent versions of Chrome, Firefox, and Babel says. The above syntax 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 in the official docs or specification.

Solution

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.".

However, if we do want to capture the args for your arrow function, we can simply use a rest parameter (BabelMDN).

The same above code can be restructured this way:

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

And here we go!

Console Chrome

We have a clear winner now! Also, a few notes regarding the above use. Rest parameters can be combined with other positional parameters, but must always be included as the last parameter. Another example showing both positional and rest parameters can be seen here.

((a, b, c, ...rest) => console.log (a, b, c, rest))("Apple", "Ball", "Cat", 1, 2, 3);

With Google Chrome's Dev Tools, we get this:

Chrome Console

But at the same time, the good part of JavaScript interpreters are the way they give the error messages. Say, you put the Rest parameters in the middle or at the front, this is what the code looks like.

((...rest, a, b, c) => console.log (a, b, c, rest))(1, 2, 3, "Apple", "Ball", "Cat");

And with our all good Chrome Console, we get an Uncaught SyntaxError:

Chrome Console

Summary

Now we now know what could be the best way to add the arguments to fat arrow functions. We also know now how to go around the official specs (I mean, thinking out of box) and achieve what we are expecting. I really hope this has helped someone who's struggling with this concept.



comments powered by Disqus