43

Looking at the doT.js source:

https://raw.github.com/olado/doT/master/doT.js

What does this do?

(function(){ return this || (0,eval)('this'); }()).doT = doT;

To me it looks like it's creating a global var, window.doT. If that's all it's doing, then why not:

window.doT = doT;

?

JstnPwll
  • 8,682
  • 2
  • 29
  • 55
Fergal
  • 2,444
  • 2
  • 33
  • 47

1 Answers1

56

It's getting a reference to the global object, in order to assign doT to it. This is generally done because with a JavaScript library/framework/etc, its one global identifier needs to be exposed to the outside world.

As for why it's not simply window.doT = doT;, it's because the global object isn't always window, for example, in a non-browser environment. It's also possible to have window assigned to somewhere else at the point this code is executed.

How it works

If this is already truthy, for example, an object such as window, it will return that. It's likely it will be window (at least in the browser), as a plain function call should have its ThisBinding set to the global object. Otherwise, it will execute eval() in the global scope because an indirect call to eval() will set its scope to global, as opposed to the calling environment's scope.

To achieve an indirect call, you have to invoke eval() indirectly, i.e. you can't just call it with eval(). You can use (0, eval) to invoke it. This relies on the comma operator returning the last evaluated expression, in this case eval. It doesn't matter what the preceding operands are. Similarly, (0||eval)() would work.

As for why the body is this, that is the argument to eval(), that is the code to be executed as a string. It will return the this in the global scope, which is always the global object.

It's not really relevant nowadays, but in older IEs, you'd need to use execScript() to execute code in the global scope. I can't remember exactly what versions of IE this was necessary for.

Community
  • 1
  • 1
alex
  • 438,662
  • 188
  • 837
  • 957
  • 7
    Why `this || (0,eval)('this')`? – Waleed Khan Jan 02 '13 at 10:02
  • By "indirect", do you mean `(0,eval)(args)`? – Waleed Khan Jan 02 '13 at 10:04
  • What would be the difference of `(0,eval)('this')` and `eval('this')` from the result point of view? – zerkms Jan 02 '13 at 10:08
  • 3
    The latter would execute in the containing scope's environment, where the `ThisBinding` may be different. – alex Jan 02 '13 at 10:08
  • If forcing `eval` to be evaluated (no pun intended) as an expression changes its scope to global, wouldn't `(eval)()` work as well? – ErikE Jan 02 '13 at 10:13
  • @zerkms This is wrong, because from snippet we have a call to an anonymous function, i.e. there is no `.apply` called. I think that the only case when `this` can be undefined is when the code is called in a strict block of code ( i.e. `"use strict";` ). – freakish Jan 02 '13 at 10:13
  • @freakish: `apply` was used to set the different scope to the function call. – zerkms Jan 02 '13 at 10:15
  • `(0,eval)('this')` is equivalent to `var e = eval; e('this')` as demonstrated here: http://jsfiddle.net/mbest/DBhKT/1/ – Michael Best Jan 02 '13 at 10:15
  • Nvm on deleted comment, Alex, clear now what the counterpoint was. – ErikE Jan 02 '13 at 10:15
  • @zerkms Yeah, but there is no scope change in OP's code. And it cannot be because of anonymous call. – freakish Jan 02 '13 at 10:17
  • @freakish: In op's code the scope is not defined initially. I mean - you cannot be for sure what it is. While my code was to demonstrate that whatever scope you have - you'll get the `window` instance by the latter call. – zerkms Jan 02 '13 at 10:18
  • @zerkms You are wrong. The scope of a holder doesn't matter, because it's an anonymous function. Unless the code is in strict mode anonymous function's `this` is always a top object. Fiddle: http://jsfiddle.net/tgtnm/1/ – freakish Jan 02 '13 at 10:20
  • @freakish: "anonymousity" has nothing to do with the scope. There is no difference between "anonymous" and "named" functions in how they behave. Still, I don't see your point. – zerkms Jan 02 '13 at 10:25
  • @zerkms Tfu, I think I'm misusing "scope" word. One more time. What I'm saying is is that your jsFiddle changes `this` because of `.apply` call. There is no `.apply` in OP's code ( hence the question: why `this || ...` ? ). Unless there is something more between characters in this one line of code ( and it doesn't look like that ) then `this` will always be the top object unless the code is called in a strict code block ( see my jsFiddle ). – freakish Jan 02 '13 at 10:30
  • @freakish: "There is no .apply in OP's code" --- I know that. I used it to artificially change the scope to demonstrate that `eval` trick works. – zerkms Jan 02 '13 at 10:32