Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

good way to validate the number of arguments to an arrow function?

obviously arguments.length does not work.

I can change the signature to f: (...args) => { if (args.length>0) { ..}; };

But this removes the parameter information from the function declaration .

Any better way ?

like image 686
kofifus Avatar asked Sep 11 '16 01:09

kofifus


People also ask

How can you determine the number of arguments passed to a JavaScript function?

length property provides the number of arguments actually passed to a function.

How do you write a function that accepts any number of arguments?

When you call a function in JavaScript, you can pass in any number of arguments, regardless of what the function declaration specifies. There is no function parameter limit. In the above function, if we pass any number of arguments, the result is always the same because it will take the first two parameters only.

Can arrow functions have arguments?

Arrow functions do not have an arguments binding. However, they have access to the arguments object of the closest non-arrow parent function. Named and rest parameters are heavily relied upon to capture the arguments passed to arrow functions.

Do arrow functions always require an argument?

Arguments binding Arrow functions do not have an arguments binding.


2 Answers

The short answer is: "no", or "maybe".

The longer answer is: from MDN :

An arrow function expression has a shorter syntax compared to function expressions and lexically binds the this value (does not bind its own this, arguments, super, or new.target). Arrow functions are always anonymous. These function expressions are best suited for non-method functions and they can not be used as constructors.

The main use for arrow functions are for callbacks, to execute code as if it was executed in its parent context. Thus preventing the annoying and ugly const that = this; requirement and does it implicitly.

For this reason, and since it is executed anonymously, within the parent's context, there is no arguments, or rather the value is of the parent's context. Arrow functions solve only a general use case, not every one.


Solution 1 : legacy or "naïve" implementation

// const that = this;
var that = this;

...
  f: function (a, b, c) {
    ...
  }
...
  • Pros
  • (currently) slightly faster than arrow functions
  • possess their own context (i.e. arguments, etc.)
  • can safely be implemented in all browsers and environments
  • Cons
  • annoying that (or some other var name) instead of this.
  • function cannot be external, or lose that reference

Solution 2 : function binding (ES5)

...
  f: (function (a, b, c) {
    ...
  }).bind(this)
...
  • Pros
  • "correct" this is available
  • can pass any external function reference (i.e. reuse code)
  • possess their own context (i.e. arguments, etc.)
  • Cons
  • (currently) slightly slower than arrow functions
  • unexpected results if the function reference was previously bound
  • no support for IE8 and perhaps other browsers (I had to mention this, even if I cannot care less for IE8)

Solution 3 : Destructuring assignment (ES6)

...
  f: (...args) => {
    const [a, b, c] = args;

    ...
  }
  g: (a, b, c, ...others) => {
    ...
  }
...
  • Pros
  • anonymous function
  • access to parent context seemlessly
  • exhibit a similar behaviour
  • Cons
  • may require destructuring
  • (currently) slightly slower than a standard function
  • not real arguments instance
  • requires a transpiler (ex: Babel) to run in the browser, which will probably transpile into a "legacy" implementation
like image 170
Yanick Rochon Avatar answered Oct 15 '22 15:10

Yanick Rochon


You've already got this figured out, spread operator + .length will give you the information you need if you are using arrow functions. I would consider the particular use-case you are presenting (where you need to preserve parameter information and know the length of the arguments) as more well suited to a non-arrow function:

 f: function(a, b, c) { console.log(arguments.length); }

If you are using arrow functions to preserve the parent context, you can always add .bind(this) to the end (and incur a small performance penalty).

I don't know exactly what you need to accomplish, but if you aren't trying to write a function with unknown arity, perhaps default arguments would allow you to handle cases where a user forgets a required parameter? ...or you could pack your arguments in an object and use Object.keys to determine the length:

let f = (args) => console.log(Object.keys(args).length);
f({ a: 1, b: 2, c: 3 });

This would preserve parameter information and allow you to ascertain the length of the arguments.

like image 28
Rob M. Avatar answered Oct 15 '22 15:10

Rob M.