0

This is b.js

var something = "hooorraaaaay!!!";

And this is a.js

require( './b.js' );

console.log(something);

Why isn't something being recognised within a.js. I understand that it has been declared with var, but my understanding is that any variable declared outside a function should act global. So why isn't this working?

Barmar
  • 741,623
  • 53
  • 500
  • 612
Grateful
  • 9,685
  • 10
  • 45
  • 77
  • 1
    You aren't exporting it. – zerkms Sep 14 '15 at 02:33
  • can you give me an example please? – Grateful Sep 14 '15 at 02:33
  • http://openmymind.net/2012/2/3/Node-Require-and-Exports/ (just a random link from google) – zerkms Sep 14 '15 at 02:34
  • 1
    @Barmar: it's a very wild guess that they use `requirejs`, one might have such code *without* using `requirejs` easily. – zerkms Sep 14 '15 at 02:35
  • Please show us the definition of your `require` function. – Barmar Sep 14 '15 at 02:37
  • @zerkms I haven't fully read it yet, but it looks excellent. Thank you. However, if I simply remove `var` everything works... without all that exporting stuff. I was under the impression that `var` outside of a function is like a global variable... and the global version seems to work. So why not the `var`? – Grateful Sep 14 '15 at 02:37
  • @Grateful perhaps because your assumption that `var` outside functions when using modules is in global scope is not entirely correct. – zerkms Sep 14 '15 at 02:38
  • @Barmar It's built into nodejs. – Grateful Sep 14 '15 at 02:39
  • @zerkms Well, sure... it would have worked otherwise. So can you kindly explain the differences. I would really appreciate it. – Grateful Sep 14 '15 at 02:40
  • @Grateful "perhaps" there is because I'm not sure as well :-D I just don't treat them so and I was never curious why it's like that since I wouldn't use it anyway. – zerkms Sep 14 '15 at 02:42

2 Answers2

2

Node modules are each in their own scope. By default, nothing in module a is visible to module b. Doing a require() on a module is NOT like including the source. It loads the file runs the code and then the only things that are available to the outside world are:

  1. Any functions or properties that are explicitly exported from the module by assigning to module.exports.
  2. Any functions or properties that are explicitly assigned to the global object in node.

So, if you want something in b.js to be exposed to the outside world, you do like this:

// b.js

module.exports.callMe = function() {
    console.log("I'm in module b");
}

And, then in a.js, you can do this:

// a.js
var b = require('./b.js');
b.callMe();

This is how the module system works in node.js. It is very different than just including a <script> tag in a browser web page. You can read more about the module system in these references:

Understanding module.exports and exports in Node.js

What is the purpose of Node.js module.exports and how do you use it?

Node.js Handbook - How require() Actually Works


Internally, node.js loads a module's code and then inserts it into a wrapper function. So, each top level variable in a node module is actually only a local variable in that module function. This is why nothing is globally declared or shared by default. It is done this way on purpose so that each module comes with it's own private area for storing it's state and will not, by default, interfere with the variables of any other module.

You then explicitly export only the property/function interfaces that you want to make public and even then, they are still not exported as public symbols so again they cannot conflict with anything else.

So, the b.js code above actually gets transformed into this when node.js runs it:

(function (exports, module, require, __filename, __dirname){
    module.exports.callMe = function() {
        console.log("I'm in module b");
    }
})(...);

The (...) contains actual variables that are passed to the module.

Community
  • 1
  • 1
jfriend00
  • 683,504
  • 96
  • 985
  • 979
0

Let me assume you are using node.js judging from the require function.

node.js wraps each file in its own scope. this has nothing to do with the use of var keyword. every file in node.js is called a module.

Now let's say you want to include a module, here comes require, you have used it right. But since your module doesn't export anything, it's useless when it's included in some other module.

So at the end of your b.js file, add the following line :

module.exports.something = something;

Now we can finally use our exported variable :

var b = require('./b.js');
console.log('Something is : ' + b.something);
Lyes BEN
  • 990
  • 4
  • 14
  • Oh, wow. Thank you for the essential bit of information. Given all that, what would be the difference between using a local `var` variable vs one without `var` (given that both are exported) ? – Grateful Sep 14 '15 at 02:56
  • I think in this case it doesn't make a difference, but It is still considered good practice to always use `var` keyword. – Lyes BEN Sep 14 '15 at 02:58
  • Actually, I forgot to mention that if I simply removed `var` (i.e. make it global), it WAS recognised within `a.js`.... even without all that exporting stuff. – Grateful Sep 14 '15 at 03:00
  • So I guess, declaring a variable without `var` enables it for usage throughout the files without the need for exporting. – Grateful Sep 14 '15 at 03:01