Jeff Cyr
Jeff Cyr

Reputation: 4864

node.js: Confusing usage of 'this' in the global scope

I've been toying with node.js lately and I ran into a weird behavior about the usage of this in the global scope of a module.

this is bound to module.exports in the global scope:

console.log(this === exports); // -> true

But this is bound to global in a method scope:

(function() { console.log(this === global); })(); // -> true

This also lead to this confusing behavior:

this.Foo = "Weird";
console.log(Foo); // -> throws undefined

(function() { this.Bar = "Weird"; })();
console.log(Bar); // -> "Weird"

I guess that the solution is to never use this in the global scope and explicitly use extends or global instead, but is there a logic behind all this or is it a bug or limitation in node.js?

Upvotes: 10

Views: 290

Answers (3)

Bijou Trouvaille
Bijou Trouvaille

Reputation: 9434

I don't know if this is the exact intention of Node.js team, but I would be surprised if it was not. Consider this example ran in the dev console of a browser (e.g. chrome):

var x = function(){console.log(this)}
a = {}
a.x = x
a.xx = function(){x()}

a.x()
>> Object
a.xx()
>> DOMWindow
x()
>> DOMWindow

As you can see executing a method without specifying its context sets the context to be the global one. In this case the DOMWindow object.

When you are inside a module your context is the module, but executing a method in it without specifying a context with .call or .apply or obj. will use the global context, global, instead of the local one, module.exports.

Upvotes: 1

Dagg Nabbit
Dagg Nabbit

Reputation: 76736

In working on a simple CommonJS modules implementation, I had to think about what to do with this in the global scope of the module; it's not addressed by the spec.

I also set it up as the exports object at first, because I thought that would be useful, but later found some code I needed to "modulize" that was using this to get a handle to the global object, so I changed this back to the global object to provide as close of an environment to "normal" as possible for module code.

We can only guess at why node is set up the way it is (or ask the author), but my guess is it was done simply because it seemed like a useful idea, similar to the way you can give the module object an exports property in node and have it reflected in the module's actual exports (this behavior also isn't part of the spec, but doesn't go against it either).

As for the part of your question about this referencing global in functions, as the other answers explain, that's just the way this works; it's not a node-specific behavior, it's a weird javascript behavior.

Upvotes: 1

jAndy
jAndy

Reputation: 235982

The "logic" behind that is, that the value of this always depends on how a function is invoked.

In your case, you have a self-executing anonymous function, there, this always references the global object (non strict mode) or undefined (ES5 strict).

If you want to access the "outer" this value, you could either store a reference before executing that function, like

var outerScope = this;

(function() { outerScope.Bar = "Weird"; })();
console.log(Foo); // -> throws undefined

or re- .bind() the functions scope yourself, like

(function() { this.Bar = "Weird"; }).bind(this)();

Upvotes: 7

Related Questions