0

Is there a way to tell the difference between this

((a=true)=>{return a})(true)

And this?

((a=true)=>{return a})()

They both return true - how can I tell whether that true is coming from the default value of the argument, or from the value passed in to that parameter?

  • Is it possible from outside the function?
  • Is it possible from inside the function?
9
  • 4
    if you use a "regular" function rather than an arrow function, you can check arguments.length Commented Mar 28, 2017 at 23:47
  • 3
    Using arguments in strict mode functions is perfectly valid. Commented Mar 29, 2017 at 0:08
  • 2
    @FREE_AND_OPEN_SOURCE But accessing .length like in JaromandaX's suggestion is fine in strict mode. Commented Mar 29, 2017 at 0:15
  • 2
    @FREE_AND_OPEN_SOURCE - arguments.length is perfectly cromulent in "strict mode", so mentioning it's unavailability would be erroneous Commented Mar 29, 2017 at 0:15
  • 3
    In general, you should not use default values when you need to distinguish those cases. What is your actual problem? Commented Mar 29, 2017 at 0:30

4 Answers 4

1

Is there a way to tell the difference between these two?

No. Arrow function doesn't support argument object, so there is no way to check this.

But, if you are using non-arrow functions, you can get arguments number from inside the function. For example:

(function(a=true){return arguments.length;})(); // 0
(function(a=true){return arguments.length;})(true); // 1

You can easily figure out how to extend this to multiple arguments.

Sign up to request clarification or add additional context in comments.

2 Comments

it may be worth mentioning that accessing arguments.length is perfectly valid in strict mode
@JaromandaX. Ok, updated. But I mean, exploiting properties of arguments object may sometimes expose possibilities such as reading source code of currently executing function or similar things. Anyway, I agree, I don't see how that may influence finding answers to that particular question.
0

You cannot tell the difference in your specific examples, and there is no way to tell from outside the function definitely. The only exposed info is what you explicitly expose with your return value, which is just the boolean.

From inside the function, you can tell the difference if you rewrite your logic. You could change your function from

((a=true)=>{
  return a;
})(true)

to

((...args)=>{
  const a = args[0] === undefined ? true : args[0];

  if (args.length > 0) console.log("passed arg");
  else console.log("passed no arg");

  return a;
})(true)

Note that you cannot combine this with default value syntax, so if you'd have to rewrite it to use rest syntax.

Alternatively, you could use a normal function instead of an arrow, and use arguments, however that is also a potentially difficult change if your real-world case relies on the arrow-function's lexical this. e.g.

(function(a = true)=>{
  if (arguments.length > 0) console.log("passed arg");
  else console.log("passed no arg");

  return a;
})(true)

2 Comments

Instead of arguments.length > 0 I'd check for arguments[0] !== undefined as that's what the default initialiser uses
My assumption was that the question was detecting the presence of an arg being passed, so it should count even if the user did foo(undefined). But it was a bit unclear.
0

Although not ideal in every way, one solution might be:

(a=undefined) => {
  let is_default = false; 
  if (a === undefined) {
    is_default = true;
    a = true;
  } 

  return a
}

3 Comments

The main downside is that this doesn't catch if you pass an argument but the value is undefined.
A default value of undefined is pretty useless, as that's the default default value. (The only difference is the arity of the function)
Yes, for pure JS it wouldn't make a difference. I did it for 2 reasons, one it makes it obvious that there is a default intent and for the benefit of some type inference checkers
0

If you really want to use arrow functions, you can achieve a robust (if convoluted) result using Symbol and a wrapping IIFE

var fn = ((def) => 
    (a = def) => {
        if(a === def) {
            console.log('defaulted');
            a = true;
        }
        console.log('a is', a);
    }
)(Symbol());

both fn() and fn(true) will result in a is true - however, fn() will also output defaulted and then set a = true - though this last step I guess doesn't have to done, depends on what the real content of the real function you really want to "detect" this in

Or, a better way as pointed out by @Bergi (I keep forgetting about the block scope in ES6+ :D )

var fn; 
{ 
    const def = Symbol(); 
    fn = (a=def) => {
        if(a === def) {
            console.log('defaulted');
            a = true;
        }
        console.log('a is', a);
    }; 
}

1 Comment

How about var fn; { const def = Symbol(); fn = (a=def) => {…}; }?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.