1

I don't know exactly what to the call the question yet. I will update it when somebody can tell me what I'm actually looking at...

I was looking at some compiled code (from Babel) and it produced this:

(0, _posSaleTipJs.shouldShowTippingOnCheckoutFlow)()

What the!? After some digging it looks like you can use any number of arguments but it always only cares about the last one. What is this syntax called, what does it mean and how is it useful?

The original code it was compiled from was:

shouldShowTippingOnCheckoutFlow()
Elliot Chance
  • 5,526
  • 10
  • 49
  • 80

2 Answers2

4

You can read about the comma operator:

The comma operator evaluates each of its operands (from left to right) and returns the value of the last operand.

Example

(x += 1, x)

produces the same result as:

++x

What happens with the (0, ...) notation

The difference between:

_posSaleTipJs.shouldShowTippingOnCheckoutFlow()

and:

(0, _posSaleTipJs.shouldShowTippingOnCheckoutFlow)()

is that the called function will get a different value of this.

In the first case this will be synonymous for _posSaleTipJs, while in the second case, this will remain the global object (or undefined in strict mode, see Babel's strict mode transform plugin).

The second effect is the result of the comma operator that returns -- in this case -- a function reference, but one that has lost its original context.

The following ES6 arrow function and immediate call would have the same effect:

((func) => func())(_posSaleTipJs.shouldShowTippingOnCheckoutFlow);

But still, the (0, ...)() notation seems the most concise way to call the function while keeping this global or undefined.

trincot
  • 317,000
  • 35
  • 244
  • 286
  • I can't figure out the use of the comma operator in the example OP provided. Why not directly call `_posSaleTipJs.shouldShowTippingOnCheckoutFlow()`. Any idea? – Soubhik Mondal Mar 01 '16 at 07:22
  • 1
    The original call didn't have a base object ("context") so the results are the same, both are called with *this* initially set to undefined, what it's set to inside the function (i.e. undefined or the global object) depends on whether the code is strict or not respectively. – RobG Mar 01 '16 at 07:38
  • 1
    True, although we don't know from the question what `this` would have already been (in the original code) before the call was made. I assume that Babel follows this pattern even if it might not be necessary in some cases. – trincot Mar 01 '16 at 07:46
  • Thanks for the explanation, but since we can use `_posSaleTipJs.shouldShowTippingOnCheckoutFlow.apply(this)` for the same purpose, I'm wondering if using the comma operator has some performance benefit? – Soubhik Mondal Mar 01 '16 at 07:47
  • 2
    I think it might have a slight performance benefit: intuitively a call to *apply* seems to be heavier than applying the `,` operator. But really, with all those smart optimisations in modern JavaScript parsers, it is hard to say. The `,` notation is also a bit shorter in number of characters. – trincot Mar 01 '16 at 07:53
0

The first part of the code

(0, _posSaleTipJs.shouldShowTippingOnCheckoutFlow)

returns the value of _posSaleTipJs.shouldShowTippingOnCheckoutFlow. The return value is obviously a function. By using parentheses () at the returned function

(0, _posSaleTipJs.shouldShowTippingOnCheckoutFlow)()

you actually call the function. So as a result, it calls your function shouldShowTippingOnCheckoutFlow.

There could be several reasons why the compiler produced this kind of code:

  • Minification
  • Performance optimization
  • Scope isolation

I would need to see bigger portion of your code to say how the compilation helped in your case.

Anton
  • 2,458
  • 2
  • 18
  • 30
  • Scope isolation? How can a call affect scope, it's lexical (i.e. based on where the call is made, not now). – RobG Mar 01 '16 at 07:41
  • @RobG, well, I have never worked with Babel, but in general if we talk about JS preprocessors you may have a file which represents a module and all functions defined in the module are during the compilation isolated from the global scope so they are available just within the module. e.g. function in module 1 defined as `function myFunc() { ... }` would be compiled as `module1.myFunc = function() { ... }` and called as `module1.myFunc()` instead of just `myFunc()`. Just please notice I really speak in general, might not be your case at all. – Anton Mar 01 '16 at 07:49