2

I'm trying to understand module.exports better. As I understand it, it can be used as a two way communication (you can send and receive data to the module.

However, this is not working as I expected:

File1.js:

var Test = require("./Balances")
Test.push(12)

Balances.js:

var arrays = [10, 11];
module.exports = arrays

File2.js:

var Test = require("./Balances")
setInterval(function(){console.log(Test)},2000)

What I want is to be able to add to the array from File1, and read the output in File2.

File2 reads the initial array just fine, but the value I push never shows in File2.

However, if I add a console.log(Test) in File1, that pushed value does appear there. Upon rerunning File1, I don't however see [12, 12] , only [ 12 ], which means the first push never got written in the Balances array.

Any idea why?

Wannes
  • 83
  • 1
  • 3
  • 11
  • what do you mean with `rerunning File1` and `written in the Balances array`? How do you load these scripts? – Thomas Jan 01 '18 at 02:47
  • I load these scripts from commandline. What I mean is that the array in balances.js should have an extra 12 at the end. Not in the file itself ofcourse, but in memory. This however doesn't get reflected in file2, which reads the array every 2 seconds. – Wannes Jan 01 '18 at 02:58
  • So you first execute `file1` in the commandline, and then you execute `file2`? But you know that these two executions are completely independant of each other, and they don't share any memory or state whatsoever. – Thomas Jan 01 '18 at 03:01
  • Aha, did not know that. I was basing this whole ordeal on the last answer fron this question: https://stackoverflow.com/questions/17120117/sharing-modifying-a-variable-between-multiple-files-node-js – Wannes Jan 01 '18 at 03:16

3 Answers3

4

When you import a variable from another javascript module, you get that variable by value, not by reference (you create a copy of the value at the given memory address, you don't simply get a pointer to that same exact variable). Therefore, you have only mutated the Test variable in File1.js; to reflect those changes in your console.log in File2.js you would have to re-export your mutated variable from File1.js and import that into File2.js, and then do the log.


Here is analysis of your code:

File1.js:

// creates copy of the `Balance.js` `arrays` variable
// stores value in new variable `Test`
var Test = require("./Balances") // => [10, 11]
// pushes 12 to the copy
Test.push(12) // => [10, 11, 12]

File2.js:

// creates copy of the `Balance.js` `arrays` variable
// stores value in new variable `Test`
var Test = require("./Balances") // => [10, 11]
// This interval does nothing. The fact is, the mutated
// `arrays` var from `File1.js` does not effect the
// `arrays` var in any other modules scope.
setInterval(function(){console.log(Test)},2000) // => [10, 11]

This is all assuming you have additional code not seen here that is required and executed from an entry point. As Thomas said in the comments, there is no state persisted between running individual scripts.


To accomplish what you're attempting in your post:

Balances.js:

var arrays = [10, 11]
module.exports = arrays

File1.js:

var test = require('./Balances')
test.push(12)

module.exports = test

File2.js:

var test = require('./File1')
function action() {
  console.log(test)
}

module.exports = action

main.js (entry point):

var action = require('./File2')
action() // => [10, 11, 12]

run $ node main.js

Hope this helps!

Charles Kenney
  • 360
  • 3
  • 12
  • 1
    That clarifies a whole lot! Thank you. Is there a better way to get an array from one file to another, without using a JSON file, and without directly requiring eachother? – Wannes Jan 01 '18 at 03:18
  • @Wannes glad to hear it. I've added an example for you. I'm assuming you are doing this to learn more, because this sort of 'importing exported imports' is confusing and would never be necessary in the real world. Typically all this would happen in a single scope – Charles Kenney Jan 01 '18 at 03:31
  • 1
    **NOOOO** modules don't export a copy of the data, neither does `require()` return a clone. All you need is a common entry point that requires both Files into the same application. – Thomas Jan 01 '18 at 12:13
  • Thomas, I think you meant to say modules don't export a copy of the data, neither does `require` **in the case of a standalone import**. But clearly my example is a derived import. Clearly Wannes is new to the language, I didn't want to deviate from how his attempted code was written for simplicity. Please read carefully – Charles Kenney Jan 01 '18 at 18:03
0

It had to have never gotten pushed because you didn't actually require File1.js anywhere. This main.js works exactly as expected with the original File1.js, File2.js, and Balances.js files. (You probably wanted setTimeout, and as mentioned that had no effect anyhow, but it does work.)

require('./File1')
require('./File2')

Yes, modifying passed non-primitives updates the original item. They are not copied. Don't spend the next few years on a redundant construct to rebuild what is already happening.

Ryan Hanekamp
  • 558
  • 4
  • 6
0

Technically you can use modules like that, but I'd avoid that. Mutating state like that can lead to a lot of problems, especially if it is done in distributed modules.

And out of a sudden you have some error or unwanted behaviour that seems to come out of nowhere. Because its source is in an completely unrelated part of your app. Have fun, finding/debugging that.

I'd rather use modules as read-only sources for configs and stuff, or export a self-contained API that manages these mutations and everything else that happens in that module.


Back to you question

all you need is a common entry point that loads both modules in the same application.

That's probably ýour misconception. every time you call node ... you start a seperate application with seperate memory and state. It loads the files you tell it to, executes the code and eventually finishes. Like opening two sites in the browser, one loading File1, the other one loading File2.

So, you can create a common entry point like main.js

require("./File1");
require("./File2");

and then start the application at that common entry point node main.js

Or you can run node -i -r "./File1" -r "./File2" and start typing more JS.

Thomas
  • 11,958
  • 1
  • 14
  • 23