67

I found this code in someone's code, it sound like this:

(0, function (arg) { ... })(this)

After I try to play around like below,

(0, function (arg) { console.log(arg) })(2);
console.log((0, 1, 2, 3));
(0, function plus1 (arg) { console.log(arg + 1) }, function plus2 (arg) { console.log(arg + 2) })(5);

I found that it will always return last item in the bracket.

I wonder what is the name of this programming pattern and what is the use case?

Mohamed Allal
  • 17,920
  • 5
  • 94
  • 97
Simon
  • 1,426
  • 3
  • 16
  • 24

3 Answers3

75

In this particular case it seems superfluous, but sometimes this approach is useful.

For example, with eval:

(function() {
  (0,eval)("var foo = 123"); // indirect call to eval, creates global variable
})();
console.log(foo);            // 123
(function() {
  eval("var bar = 123");     // direct call to eval, creates local variable
})();
console.log(bar);            // ReferenceError

It's also useful when you want to call a method without passing the object as the this value:

var obj = {
  method: function() { return this; }
};
console.log(obj.method() === obj);     // true
console.log((0,obj.method)() === obj); // false

Also note that, depending on the context, it might be the arguments separator instead of a comma operator:

console.log(
  function(a, b) {
    return function() { return a; };
  }
  (0, function (arg) { /* ... */ })(this)
); // 0

In this scenario, (0, function (arg) { /* ... */ }) are the arguments (a=0, b=function (arg) { /* ... */ }) to the function

function(a, b) {
  return function() { return a; };
}

rather than the comma operator. (Then, the (this) at the end is function call with argument this to the returned function function() { return a; }. But this part is not relevant to the comma operator/argument separator difference)

Eric
  • 5,686
  • 2
  • 23
  • 36
Oriol
  • 274,082
  • 63
  • 437
  • 513
  • 20
    ... you just gave me a bunch of other reasons to claim that JavaScript design is broken... – Bakuriu Dec 05 '16 at 07:44
  • Wouldn't a better and more readable way to do your second example be `obj.method.call(window)` ? – Whelkaholism Dec 05 '16 at 09:55
  • 3
    @Whelkaholism It should be `obj.method.call(undefined)` if you want it to be equivalent in strict mode too. But that requires the function to inherit `call` from `Function.prototype`. Not all callable objects inherit from `Function.prototype`, and even if they do, `call` could be shadowed. – Oriol Dec 05 '16 at 16:10
  • 2
    Can anyone explain why this works? It appears that javascript wraps a function reference with another function whose first parameter is scope or context? What could you use to replace the 0 that would make the above express true again? – latj May 26 '17 at 19:47
  • 2
    @latj `obj.method` produces a reference, and thus when you call it, the base `obj` is used as the `this` value. But when you use the comma operator (it doesn't matter whether you use `0` or whatever), the reference is resolved into a value. – Oriol Apr 02 '18 at 19:20
  • I have been coding for 10+ years, really can't understand this.... – Siwei Jan 11 '22 at 01:35
  • the eval expression `(function() { (0, eval)("var foo = 123"); })();` is equivalent to `(function() { eval.call(this, "var bar = 123"); })();` . – Danilo Gómez Jun 20 '22 at 23:24
3

It is a comma operator wrapped with a self-executing anonymous function. However, I have no idea as to why the meaningless 0 was included except for obfuscation purposes.

Joseph Shih
  • 1,244
  • 13
  • 25
3

typical example could be,

for(var i=0,j=10; i < j; i++){
 // code ...
}

comma operator would evaluate expressions from left-to-right and return result of right most expression

// e.g.

var a = 1, b= 2, c = 3, d = function(){ console.log("a => " +  a) }()
A.T.
  • 24,694
  • 8
  • 47
  • 65
  • 3
    I think the `var a = 1, b = 2, c = 3` is not a "comma operator" but a var declaration. `a`, `b`, and `c` here are created in the local scope so they each are actually declared with a `var`. To illustrate, here's 2 functions: `function foo(){var a = 1, b = 2, c = 3;}` `function bar(){var a = (1, b = 2, c = 3);}`. If you run `foo();`, `a`, `b`, and `c` would only exist in the local scope. However, if you run `bar();`, you'll find `b` and `c` in the global scope! This is because the `(1, b = 2, c = 3)` portion is now your "comma operator". – Joseph Shih Dec 12 '18 at 07:41
  • This was the source: https://www.i-programmer.info/programming/javascript/6524-the-confusing-comma-in-javascript.html Under the section "This Is Not The Comma You Are Looking For" – Joseph Shih Dec 12 '18 at 07:43
  • _Now_ I get it - I guess I needed this connection to something I know of (usage of commas in a declaration). – la Fleur Mar 13 '23 at 18:48