0
votes

I'm learning about CommonJS from this blog and having trouble understanind the below in regards to the code:

In this example, we basically make two copies of the module: one when we export it, and one when we require it. Moreover, the copy in main.js is now disconnected from the original module. That’s why even when we increment our counter it still returns 1 — because the counter variable that we imported is a disconnected copy of the counter variable from the module.

// lib/counter.js

var counter = 1;

function increment() {
  counter++;
}

function decrement() {
  counter--;
}

module.exports = {
  counter: counter,
  increment: increment,
  decrement: decrement
};


// src/main.js

var counter = require('../../lib/counter');

counter.increment();
console.log(counter.counter); // 1

So if 2 copies are created, then wouldn't each copy have their own version of counter and increment? Thus each one would be connected to their own function of increment? The author is saying that there is 1 copy of counter, increment, and decrement that is in module.exports and another copy in the var counter = require('../../lib/counter') so shouldn't the counter.increment calling the increment function in the require copy and the console.log(counter.counter) return the connected counter in the require copy?

1

1 Answers

3
votes

I think the statement was made to bring about the contrast between ES6 modules vs nodejs CommonJS modules.Its not fully correct.

When you require a module here are some of the things you need to understand.

How require works behind the scenes ?

In short the module code required by calling require is executed and cached. Before the module code is executed Node.js will wrap it with a function wrapper (module wrapping).This ensures that top level variables(like counter) are scoped to the module rather than the global object.This means that if you are exporting a function to be used in another module it can behave as a closure with respect to the variables declared within the module.Finally the contents of module.exports is returned.

How value assignment happens with respect to primitive vs object types?

Let's look at the module.exports of lib/counter.js.
You will see that it is exporting a primitive value(counter) plus two functions(increment and decrement).counter being a primitive value is copied by its value i.e the number 1 is being set as the value for module.exports.counter whereas increment and decrement(both being first class objects) are copied by its reference.In effect both module.exports.increment and module.exports.decrement are closures with respect to the counter variable that is used within their body. You can read more on primitive vs object assignment in this post.

Finally inside main.js the counter variable(which gets assigned the contents of module.exports from counter) is a object with the following keys.

  1. counter - which is a primitive value of type number.
  2. increment - which is pointer to a closure.
  3. decrement - which is also a pointer to a closure.

Thus you can see that the counter variable inside the functions refers to the one defined within counter module.And since the counter.counter value was exported simply by its value any operation on it has no effect on the original module variable.