module.exports vs exports in Node.js

前端 未结 23 1181
自闭症患者
自闭症患者 2020-11-22 06:11

I\'ve found the following contract in a Node.js module:

module.exports = exports = nano = function database_module(cfg) {...}

I wonder what

相关标签:
23条回答
  • 2020-11-22 07:08

    Let's create one module with 2 ways:

    One way

    var aa = {
        a: () => {return 'a'},
        b: () => {return 'b'}
    }
    
    module.exports = aa;
    

    Second way

    exports.a = () => {return 'a';}
    exports.b = () => {return 'b';}
    

    And this is how require() will integrate module.

    First way:

    function require(){
        module.exports = {};
        var exports = module.exports;
    
        var aa = {
            a: () => {return 'a'},
            b: () => {return 'b'}
        }
        module.exports = aa;
    
        return module.exports;
    }
    

    Second way

    function require(){
        module.exports = {};
        var exports = module.exports;
    
        exports.a = () => {return 'a';}
        exports.b = () => {return 'b';}
    
        return module.exports;
    }
    
    0 讨论(0)
  • 2020-11-22 07:08

    why both are used here

    I believe they just want to be clear that module.exports, exports, and nano point to the same function - allowing you to use either variable to call the function within the file. nano provides some context to what the function does.

    exports won't be exported (only module.exports will), so why bother overwriting that as well?

    The verbosity trade-off limits the risk of future bugs, such as using exports instead of module.exports within the file. It also provides clarification that module.exports and exports are in fact pointing to the same value.


    module.exports vs exports

    As long as you don't reassign module.exports or exports (and instead add values to the object they both refer to), you won't have any issues and can safely use exports to be more concise.

    When assigning either to a non-object, they are now pointing to different places which can be confusing unless you intentionally want module.exports to be something specific (such as a function).

    Setting exports to a non-object doesn't make much sense as you'll have to set module.exports = exports at the end to be able to use it in other files.

    let module = { exports: {} };
    let exports = module.exports;
    
    exports.msg = 'hi';
    console.log(module.exports === exports); // true
    
    exports = 'yo';
    console.log(module.exports === exports); // false
    
    exports = module.exports;
    console.log(module.exports === exports); // true
    
    module.exports = 'hello';
    console.log(module.exports === exports); // false
    
    module.exports = exports;
    console.log(module.exports === exports); // true
    

    Why assign module.exports to a function?

    More concise! Compare how much shorter the 2nd example is:

    helloWorld1.js: module.exports.hello = () => console.log('hello world');

    app1.js: let sayHello = require('./helloWorld1'); sayHello.hello; // hello world

    helloWorld2.js: module.exports = () => console.log('hello world');

    app2.js: let sayHello = require('./helloWorld2'); sayHello; // hello world

    0 讨论(0)
  • 2020-11-22 07:09

    Even though question has been answered and accepted long ago, i just want to share my 2 cents:

    You can imagine that at the very beginning of your file there is something like (just for explanation):

    var module = new Module(...);
    var exports = module.exports;
    

    enter image description here

    So whatever you do just keep in mind that module.exports and NOT exports will be returned from your module when you're requiring that module from somewhere else.

    So when you do something like:

    exports.a = function() {
        console.log("a");
    }
    exports.b = function() {
        console.log("b");
    }
    

    You are adding 2 function a and b to the object on which module.exports points too, so the typeof the returning result will be an object : { a: [Function], b: [Function] }

    Of course, this is the same result you will get if you are using module.exports in this example instead of exports.

    This is the case where you want your module.exports to behave like a container of exported values. Whereas, if you only want to export a constructor function then there is something you should know about using module.exports or exports;(Remember again that module.exports will be returned when you require something, not export).

    module.exports = function Something() {
        console.log('bla bla');
    }
    

    Now typeof returning result is 'function' and you can require it and immediately invoke like:
    var x = require('./file1.js')(); because you overwrite the returning result to be a function.

    However, using exports you can't use something like:

    exports = function Something() {
        console.log('bla bla');
    }
    var x = require('./file1.js')(); //Error: require is not a function
    

    Because with exports, the reference doesn't point anymore to the object where module.exports points, so there is not a relationship between exports and module.exports anymore. In this case module.exports still points to the empty object {} which will be returned.

    Accepted answer from another topic should also help: Does Javascript pass by reference?

    0 讨论(0)
  • 2020-11-22 07:10

    I went through some tests and I think this may shed some light on the subject...

    app.js:

    var ...
      , routes = require('./routes')
      ...;
    ...
    console.log('@routes', routes);
    ...
    

    versions of /routes/index.js:

    exports = function fn(){}; // outputs "@routes {}"
    
    exports.fn = function fn(){};  // outputs "@routes { fn: [Function: fn] }"
    
    module.exports = function fn(){};  // outputs "@routes function fn(){}"
    
    module.exports.fn = function fn(){};  // outputs "@routes { fn: [Function: fn] }"
    

    I even added new files:

    ./routes/index.js:

    module.exports = require('./not-index.js');
    module.exports = require('./user.js');
    

    ./routes/not-index.js:

    exports = function fn(){};
    

    ./routes/user.js:

    exports = function user(){};
    

    We get the output "@routes {}"


    ./routes/index.js:

    module.exports.fn = require('./not-index.js');
    module.exports.user = require('./user.js');
    

    ./routes/not-index.js:

    exports = function fn(){};
    

    ./routes/user.js:

    exports = function user(){};
    

    We get the output "@routes { fn: {}, user: {} }"


    ./routes/index.js:

    module.exports.fn = require('./not-index.js');
    module.exports.user = require('./user.js');
    

    ./routes/not-index.js:

    exports.fn = function fn(){};
    

    ./routes/user.js:

    exports.user = function user(){};
    

    We get the output "@routes { user: [Function: user] }" If we change user.js to { ThisLoadedLast: [Function: ThisLoadedLast] }, we get the output "@routes { ThisLoadedLast: [Function: ThisLoadedLast] }".


    But if we modify ./routes/index.js...

    ./routes/index.js:

    module.exports.fn = require('./not-index.js');
    module.exports.ThisLoadedLast = require('./user.js');
    

    ./routes/not-index.js:

    exports.fn = function fn(){};
    

    ./routes/user.js:

    exports.ThisLoadedLast = function ThisLoadedLast(){};
    

    ... we get "@routes { fn: { fn: [Function: fn] }, ThisLoadedLast: { ThisLoadedLast: [Function: ThisLoadedLast] } }"

    So I would suggest always use module.exports in your module definitions.

    I don't completely understand what's going on internally with Node, but please comment if you can make more sense of this as I'm sure it helps.

    -- Happy coding

    0 讨论(0)
  • 2020-11-22 07:12

    in node js module.js file is use to run the module.load system.every time when node execute a file it wrap your js file content as follow

    '(function (exports, require, module, __filename, __dirname) {',+
         //your js file content
     '\n});'
    

    because of this wrapping inside ur js source code you can access exports,require,module,etc.. this approach is used because there is no other way to get functionalities wrote in on js file to another.

    then node execute this wrapped function using c++. at that moment exports object that passed into this function will be filled.

    you can see inside this function parameters exports and module. actually exports is a public member of module constructor function.

    look at following code

    copy this code into b.js

    console.log("module is "+Object.prototype.toString.call(module));
    console.log("object.keys "+Object.keys(module));
    console.log(module.exports);
    console.log(exports === module.exports);
    console.log("exports is "+Object.prototype.toString.call(exports));
    console.log('----------------------------------------------');
    var foo = require('a.js');
    console.log("object.keys of foo: "+Object.keys(foo));
    console.log('name is '+ foo);
    foo();
    

    copy this code to a.js

    exports.name = 'hello';
    module.exports.name = 'hi';
    module.exports.age = 23;
    module.exports = function(){console.log('function to module exports')};
    //exports = function(){console.log('function to export');}
    

    now run using node

    this is the output

    module is [object Object]
    object.keys id,exports,parent,filename,loaded,children,paths
    {}
    true
    

    exports is [object Object]

    object.keys of foo: name is function (){console.log('function to module exports')} function to module exports

    now remove the commented line in a.js and comment the line above that line and remove the last line of b.js and run.

    in javascript world you cannot reassign object that passed as parameter but you can change function's public member when object of that function set as a parameter to another function

    do remember

    use module.exports on and only if you wants to get a function when you use require keyword . in above example we var foo = require(a.js); you can see we can call foo as a function;

    this is how node documentation explain it "The exports object is created by the Module system. Sometimes this is not acceptable, many want their module to be an instance of some class. To do this assign the desired export object to module.exports."

    0 讨论(0)
提交回复
热议问题