10

While investigating google plusone scripts, I've seen following syntax many times:

(0, _.Em)();

Assuming _.Em is a function the statement above would result in calling that function, that's pretty obvious. If, on the other hand, it would be undefined, wouldn't the result be the same as doing simply _.Em() ?

Can anyone shed a light on what's idea behind using such syntax?

WTK
  • 16,583
  • 6
  • 35
  • 45
  • see also [Does the comma operator influence the execution context in Javascript?](http://stackoverflow.com/q/36076794/1048572) – Bergi Sep 16 '16 at 12:29
  • see also [Why does google main page use (0, obj.func)(args) syntax?](https://stackoverflow.com/q/19535601/1048572) – Bergi Dec 01 '19 at 13:15

1 Answers1

9

Basically, this syntax allows to call _.Em() in the context of the window object instead of _.

Assuming you have this code:

Foo = function() {
    this.foo = "foo";
};

Foo.prototype.Em = function() {
    alert(this.foo);
};

var _ = new Foo();

Issuing _.Em() will result in Em() being called in the context of _. Inside the function, the this keyword will refer to _, so foo will be printed.

Issuing (0, _.Em)() decouples the method call from the object and performs the call in the global context. Inside the function, the this keyword will refer to window, so undefined will be printed, since window does not have a foo property.

You can test the difference between the two syntaxes in this fiddle.

Frédéric Hamidi
  • 258,201
  • 41
  • 486
  • 479
  • 5
    Because evaluating `_.Em` then applying the call operator is not the same as calling `_.Em()` directly. Evaluating `_.Em` independently returns a "free function", for lack of a better term, and that function will not be tied to the `_` object anymore. The same result can be obtained by writing `var f = _.Em; f();`. In both cases, the `this` keyword will refer to `window` instead of `_` inside the function. – Frédéric Hamidi Mar 16 '12 at 10:50
  • +1, good answer. I'd like to add that this is perhaps the most pointless form of syntactic sugaring that I've ever seen in JS. `(0, )()` is exactly the same length as `.call()`, so there's no byte saving unless you remove the space after the comma (and even then it's only one). At the cost of confusing unsuspecting developers, it really doesn't seem worth using syntax like this. – Andy E Mar 16 '12 at 10:50
  • @Andy, I think it has to do with [strict mode](https://developer.mozilla.org/en/JavaScript/Reference/Functions_and_function_scope/Strict_mode). In that mode, `_.Em.call()` without arguments will call `Em()` in the context of `undefined`, not `window`, and `_.Em.call(window)` is arguably longer than `(0, _.Em)()`. – Frédéric Hamidi Mar 16 '12 at 10:54
  • So what is the (0, _.Em) doing to isolate `Em` from `_`? I know that (1,2,3) gives 3 as the result. So it seems like `(_.Em)` and (0, _.Em) should be equivalent, but `(_.Em)()` behaves just like `_.Em()` so they are clearly not the same. Also, fwiw in Chrome, the fiddle example reported `undefined`, not `window`. – Devon_C_Miller Mar 16 '12 at 11:07
  • @FrédéricHamidi: you're completely right, I had forgotten about that. I'd still rather use `.call(this)`, but I guess scripts like Google's Plus One script needs to save all the bytes it can. – Andy E Mar 16 '12 at 11:11
  • 3
    @Devon, yup, that's not just Chrome. As I said in my answer, `undefined` will be printed because `this.foo` is evaluated, not just `this` (which would print `[object Window]`). Now, `(0, _.Em)` is not the same as `(_.Em)`, as the comma operator is involved, so `_.Em` is returned as a free function before the call operator is seen. `(_.Em)` is equivalent to `_.Em` because a single expression between parentheses is always equivalent to that expression. – Frédéric Hamidi Mar 16 '12 at 11:12
  • @Andy, ah, but what if the caller does not operate in the global context? In that case `this` won't refer to `window` in the caller, and `.call(this)` will relay that object as the callee's context. – Frédéric Hamidi Mar 16 '12 at 11:15
  • @FrédéricHamidi: yes, of course, there's that too. I was simply stating that I would still choose the more verbose option for clarity. – Andy E Mar 16 '12 at 11:16
  • Actually it's in the context of `undefined`, only in sloppy-mode function it falls back to the global object. – Bergi Sep 16 '16 at 12:27