Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 313
Jeff Cyr Avatar asked Feb 28 '12 15:02

Jeff Cyr


People also ask

What is global scope in nodeJS?

While in browsers the global scope is the window object, in nodeJS the global scope of a module is the module itself, so when you define a variable in the global scope of your nodeJS module, it will be local to this module. You can read more about it in the NodeJS documentation where it says: global.

How do I use global variables in nodeJS?

To set up a global variable, we need to create it on the global object. The global object is what gives us the scope of the entire project, rather than just the file (module) the variable was created in. In the code block below, we create a global variable called globalString and we give it a value.

What is the name of the global object in the nodeJS environment?

Scripts running under Node. js have an object called global as their global object.

Which is the global available function is used to import a module in nodeJS?

In order to use Node. js core or NPM modules, you first need to import it using require() function as shown below. var module = require('module_name'); As per above syntax, specify the module name in the require() function.


3 Answers

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)();
like image 105
jAndy Avatar answered Oct 21 '22 00:10

jAndy


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.

like image 1
Dagg Nabbit Avatar answered Oct 20 '22 22:10

Dagg Nabbit


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.

like image 1
Bijou Trouvaille Avatar answered Oct 20 '22 22:10

Bijou Trouvaille