Nodejs Column - Modularization of Nodejs (module.exports and exports principles, Nodejs modularization principles)

Modularization of Nodejs

In the process of our daily web development, modularization can not be lost. Each of them has its own way of implementation. Noejs follows the commonjs specification.

  1. Think of every file as a module

  2. If a module needs to expose some data or functionality for use by other modules, write module.exports = xxx, which is called module export

  3. If one module needs to use code exported by another module, you need to use require('...')) to introduce, the return value of the require function is what the index module exposes

  4. Variables generated by all global codes in a module, functions that do not cause global pollution, are used only within a module

  5. Modules have a cache, which is cached the first time a module is imported, and then used directly when the same module is imported again

  6. Each module may depend on other modules or may depend on other modules

Use of module.exports and require

I create a new index.js

// index.js
const result = require('./test.js');
console.log(result); // Output {a: 100}

Then I'll create a new test.js

// test.js
const a = 100;
module.exports = {
    a
}

When we go to the terminal and execute the index.js file, we find that the printed result is an object because we export an object directly in test.js with a variable a in it

And if I assign a value to a naked declaration that writes a without exporting anything, I won't get anything in index.js

// test.js
const a = 100; 
// index.js
const result = require('./test.js');
console.log(result); // Output {}

As we can see from the diagram, the output is empty, so if we want to use variables or data externally, we need to use module.exports to export the variables or data that we want the external module to use and require to import them in another module.

In the test file, what we want to export is module.exports, for example, I want to export a

// test.js
const a = 100;
module.exports = a;
// index.js
const result = require('./test.js');
console.log(result); // Output is 100

In essence, module.exports is an object, and we can export multiple variables or data through module.exports

// test.js
const a = 100;
const b = 'helloWorld';
const c = {
    name: 'loki',
    age: 18
}
const foo = () => {
    console.log(c);
}  

console.log(module.exports); // Output {}

// You can write like this
/**
 * module.exports.a = a;
 * module.exports.b = b;
 * module.exports.c = c;
 * module.exports.foo = foo;
 * But it's still tiring
 * **/

//We usually write like this

module.exports = {
    a,
    b,
    c,
    foo
}
// index.js
const result = require('./test.js');
console.log(result);

So module.exports we can play around

About exports

Some friends may think that I didn't write exports, yes, I deliberately avoided them. Let me write some concepts about module.exports and exports, as well as the execution environment of some node s. You may use exports less in the future.

First let's pave the original js, in case you forget

let fstObj = {};
let secObj = fstObj;
console.log('fstObj Identical to secObj Are you??', fstObj === secObj); // true

fstObj.a = 100;
secObj.b = 200;
console.log('First Output fstObj Value of', fstObj); //{a: 100, b: 200}

fstObj = {
    c: 300
}

secObj.d = 400;
console.log('Second Output fstObj Value of',fstObj);

module.exports = {
    a,
    b,
    c,
    foo
}

The output from node index.js above is as follows

Why did b add in the output for the first time and d for the second time disappear? That's why you'll think clearly if you have a good foundation

  • At first fstObj gets an address for the reference value, so fstObj points to that reference value

  • We assign the value of fstObj to secObj. Since fstObj holds the pointer in its hand, fstObj gives secObj its own pointer. At this point fstObj and secObj point to the same address, so when I change the value of secObj, fstObj is also changed

  • Later we changed the value of fstObj directly to a new address, when secObj and fstObj no longer point to the same address, so adding the d attribute to secObj fstObj is no longer perceptible

This brings us to exports and module.exports

Take a look at an example first

// test.js
console.log('module.exports Value of', module.exports);
console.log('exports Value of', exports);
console.log('module.exports Identical to exports Are you?', module.exports === exports);
module.exports.a = 10;
exports.b = 20;
// index.js
const result = require('./test.js');
console.log('from test.js Results of Import', result);

The results are as follows

That's not enough. You'll have to look at one more

// test.js
console.log('module.exports Value of', module.exports);
console.log('exports Value of', exports);
console.log('module.exports Identical to exports Are you?', module.exports === exports);
module.exports = {
    userName: 'loki'
};
console.log('Now? module.exports Identical to exports Are you?', module.exports === exports);
exports.age = 18;
// index.js
const result = require('./test.js');
console.log('from test.js Results of Import', result);

The output is as follows

In the two examples above, we can summarize a few points

  • module.exports and exports are equal at birth and are empty objects {}, meaning they point to the same address at the beginning
module.exports = exports = {};
  • When we require a module, the code in the imported module is executed once, so when we require test.js, we output all the printed statements in the test file once

  • When we change the pointer to module.exports, exports will no longer take effect, proving that the system exported to us the value of module.exports by default

In fact, at the bottom level, the commonjs specification encapsulates each exported file in a function and passes a few parameters to the function, two of which are familiar exports and module.exports, and the function will return module.exports when it is finished

function(exports,require, module, __filename,__dirname) {
//Code we wrote
// module.exports...
// const xxx = xxx;
return module.exports
}

It's really easy to prove that since the modular code we write will be placed in the body of the function and the body will pass us these parameters, it's not good to output arguments directly on the first line of the test file

// test.js
console.log(arguments);
console.log('exports Identical to arguments[0]Are you?', exports === arguments[0]);
console.log('require Identical to arguments[1]Are you?', require === arguments[1]);
console.log('module.exports Identical to arguments[2]Are you?', module === arguments[2]);
console.log('__filename Identical to arguments[3]Are you?', __filename === arguments[3]);
console.log('__dirname Identical to arguments[4]Are you?', __dirname === arguments[4]);
// index.js
const result = require('./test.js');
console.log('from test.js Results of Import', result);

The output is as follows

And since exports will fail as long as we change the pointer to module.exports, according to our previous js padding, so it should be written in his body

function(exports, require, module, __filename, __dirname) {
    module.exports = {};
    exports = module.exports;
    // ...the code we wrote
    return module.exports;
}

So that's why I recommend you try to use module.exports instead of exports. The system always returns module.exports, and if we use exports, one day we accidentally change the value of module.exports, the code will go wrong.

summary

  • Modularization of nodejs follows the commonjs specification
  • In fact, we are able to use exports and module.exports as well as u dirname in webpack because the modularization of nodejs essentially puts each modular file into a function to execute, and the variables we can use are the parameters passed to us by the function
  • Never use exports with module.exports

At this point, the principles of Nodejs's modularization following the commonjs specification have been written, and I hope I have made it clear

33 original articles published, 11 praised, 2216 visits
Private letter follow

Tags: Web Development less Attribute Webpack

Posted on Fri, 21 Feb 2020 19:59:30 -0500 by Skepsis