8

Using Babel, I can see that

 callback = () => {};

compiles to

callback = function callback() {};

which is what I expect. However I get an error when I try to use it with ||

callback = callback || () => {}

Which I'd expect to be equivalent to

 callback = callback || function(){};

Why is this an error? Also, is there a more correct ES6 version of this familiar syntax?

Michał Perłakowski
  • 88,409
  • 26
  • 156
  • 177
1252748
  • 14,597
  • 32
  • 109
  • 229
  • 3
    Couldn't you just wrap that up `callback = callback || (() => {})` – adeneo Sep 30 '16 at 15:35
  • 2
    In similar fashion, you cannot immediately-invoke `() => {}()`; you have to write `(() => {})()`. –  Sep 30 '16 at 16:24
  • 1
    @1252748, This is a classic [XY problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). You're intermediate goal is to assign a function to a variable if the variable is unset, so you ask about `||`. But you still haven't asked a question about your primary goal: i.e., what is the context this code is written in? What problem are you trying to solve? I suspect that there's a much better solution. – Mulan Sep 30 '16 at 16:49
  • 1
    @naomik The title might be a little vague or misrepresentative, but based on the excellent answers I've received I think the intent was pretty clearly understood. – 1252748 Sep 30 '16 at 16:50
  • @1252748 you're missing my point. You're too focused on the specific issue you ran into with your attempted implementation (`||` syntax wasn't working the way you expected), but as torazaburo identified, using `||` in the first place isn't a particularly good fit for the code you've presented. I'm asking you to zoom out further and answer "what is the big-picture goal here?" or "what is a *default callback* and what value could that possibly be?" – I suspect you might be designing the function entirely wrong, hence I call this an XY problem. – Mulan Sep 30 '16 at 16:54
  • 1
    @naomik I was just curious why it didn't work man. There's not really a bigger picture. – 1252748 Sep 30 '16 at 16:58
  • 1
    @1252748 ["Dude, can we make this one part into, like, two parts, bro?"](http://imgur.com/a/9Abfz) – Mulan Sep 30 '16 at 17:22
  • See also [Why does the logical or operator (||) with an empty arrow function (()=>{}) cause a SyntaxError?](http://stackoverflow.com/q/42679078/1048572) – Bergi Apr 21 '17 at 12:24

3 Answers3

8

It fails because that is just not valid syntax.

Use the following to make it work:

callback = callback || (() => {})

If you don't wrap it that way, it would be interpreted as if you typed the following. But that is invalid syntax.

callback = (callback || ()) => {}

To extend on the evaluation of the assignment, see the specification of the AssignmentExpression. It consist of a ConditionalExpression or an ArrowFunction (or some other expressions I will disregard). So the interpreter will try to use your code as a conditional. But the () itself is not valid in that context as an expression is expected inside that ParenthesizedExpression. As a result, it will fail. If you instead group the expression as callback || (() => {}) both sides of the LogicalOrExpressions are valid expressions.

str
  • 42,689
  • 17
  • 109
  • 127
  • 1
    I see. But where in that table is the precedence for `() => {}`? – 1252748 Sep 30 '16 at 15:41
  • @1252748 You are right, the MDN link does not explicitly specify the arrow function. I added some more context to my answer, I hope that helps. – str Sep 30 '16 at 16:15
  • 1
    good explanation - as if the interpreter itself is speaking :D –  Sep 30 '16 at 17:21
  • @str I've updated the [MDN link](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence) if you want to bring it back. – jib Sep 30 '16 at 22:04
  • @jib Your [change was reverted](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence$history), "arrows are not operators". – str Oct 01 '16 at 07:29
  • @str My mistake. A note about your explanation, I don't think the parsing hinges on `()` not being a valid expression, as I can substitute the arrow function for `x => x*2` ***and*** have a valid `x` in scope, and it produces the same error for me. A more general answer might be helpful. – jib Oct 01 '16 at 15:16
  • @str I've added a note on MDN under [arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#Parsing_order) instead. – jib Oct 02 '16 at 15:37
5

Due to operator precedence, you have to wrap the arrow function in parentheses to make it work:

callback = callback || (() => {})
Michał Perłakowski
  • 88,409
  • 26
  • 156
  • 177
3

If you're planning to use the || to provide a default value for the callback parameter to a function, it's easier to just write

function myfunc(callback = () => { }) {
  callback("Hi 1252748");
}

No extra parens needed.

  • Thanks! I considered that, but to be honest, I find the default parameter for a function to be too messy looking. In fact, I don't even really like it all. It's just too much going on in the argument list. – 1252748 Sep 30 '16 at 16:29
  • Sure, but it deals with the problem of say a boolean argument with a default, which can't be easily handled by the `||` idiom. Personally, I **love** default arguments and use them all the time. –  Sep 30 '16 at 16:34
  • `"a boolean argument with a default, which can't be easily handled by the || idiom"` Can you explain what you mean? How does `||` not easily handle booleans? – 1252748 Sep 30 '16 at 16:37
  • 3
    I mean, let's say you want a parameter to default to true, and then you write `boolParm = boolParm || true`, then even if the user explicitly passes in `false`, it will be set to `true`. Same applies to any falsy valued passed in such as `0` or `""`. To handle such cases, you'll have to write out `boolParm = boolParm === undefined ? true : boolParm;` (which is actually what a transpiler would transpile a parameter default into). –  Sep 30 '16 at 16:40
  • @torazaburo I was just going to make a similar remark re: falsy values. I agree that default arguments are much better in this case. – Mulan Sep 30 '16 at 16:41
  • tbf, I'm also not sure what a default callback/continuation would even be. The only thing that comes to mind is something where `id` would be used, like: `Array.from = function(iterable, mappingFunc = x => x) { ... }`. It just suggests other problems to me. I wish we could see the rest of the OP's real code. – Mulan Sep 30 '16 at 16:45