Hacker News new | past | comments | ask | show | jobs | submit login

That's a really cool trick/abuse of syntax that goes back to the confusing `this` in javascript.

calling a method or function directly (when in the global scope) will set `this` to the global object. But calling a method or bound function could have a different `this`, and calling a function directly in another context can have a different `this`.

the `(0, funcName)` syntax works by evaluating each item in the parens, but returns the last item. (don't ask me why this is in the syntax, I genuinely don't know and have never seen it used beyond this as far as I know)

So that syntax is abused to basically (simplified here) reassign the funcName to strip out the `this` that is bound to it and reassign it to the global context.

It then evals that `this`, and returns it! Meaning it will always get the global `this`, or `globalThis`!

It would be similar to doing this:

    var thing = eval
    thing('this')



> the `(0, funcName)` syntax works by evaluating each item in the parens, but returns the last item.

This is just how the comma operator works in other languages such as C and C++: https://en.m.wikipedia.org/wiki/Comma_operator


it is! And I just now realized that I have seen it used many times before, in for loops and variable declarations.

It just seems so foreign and out of place when used outside of those instances though, and for me at least the purpose of it wasn't intuitive at all!


In C, the commas are also used in macro definitions where you need multiple statements to be output by the macro, but can’t use semicolons because the macro might expand in a context where only one statement is expected. In both the OP and this one,it comes off as clever but tricky.


so the comma operator doesn't do anything special other than return the last value - so why not just call eval directly?

If somebody rebound eval to redefine the 'this' inside - e.g., eval = (function(){myThis = ... ; return function(a){eval.apply(mythis, [a]);};})();

then calling eval with (0, eval)('this') will still not have rebinded the 'this' inside eval right? So why not just directly call eval('this')? Or am i missing the point?


It's getting to the limit of my knowledge here, so please don't take this as fact, however:

I believe it is because of a weird distinction between "direct" and "indirect" calls in javascript. The spec says that an indirect call is guaranteed to execute in the global context, but a direct call will execute in whatever context it's in.

The `(0, eval)` makes it an indirect call by evaluating an expression that returns the function.

I'm not quite sure about the details of why indirect calls are treated that way though...


This is correct, for details this is specified as point 15.1.2.1 in ES spec:

> (...) any invocation of eval that is not a direct call uses the global environment as its variable environment rather than the caller’s variable environment.

Source: https://ecma-international.org/ecma-262/5.1/


ahh, so this only applies to the 'eval' function, and not just any functions it seems.


I believe it is because of a weird distinction between "direct" and "indirect" calls in javascript. The spec says that an indirect call is guaranteed to execute in the global context, but a direct call will execute in whatever context it's in.

The `(0, eval)` makes it an indirect call by evaluating an expression that returns the function.

This is really timely. I just ran into an issue this weekend where I tried to generalize a function call like this (unaware of the direct vs. indirect semantics), and TypeScript yelled at me about it. Looks like it was trying to evaluate it in the global context, so the error makes sense now.




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: