【问题标题】:module.exports vs exports in Node.jsNode.js 中的 module.exports 与导出
【发布时间】:2011-10-31 12:45:33
【问题描述】:

我在 Node.js 模块中找到了以下合同:

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

我想知道module.exportsexports 之间有什么区别,为什么在这里使用两者。

【问题讨论】:

  • 很棒的资源:@​​987654322@ ^_^
  • 一切都与参考有关。将导出视为指向 module.exports 的局部变量对象。如果您覆盖了exports 的值,那么您将失去对module.exports 的引用,而module.exports 就是您作为公共接口公开的内容。
  • 快速总结:exportsmodule.exports 都指向同一个对象,除非您重新分配一个。最后返回module.exports。因此,如果您将exports 重新分配给一个函数,那么不要指望一个函数,因为它不会被返回。但是,如果您分配了这样的函数exports.func = function...,那么生成的东西将具有 func 属性,函数作为值。因为您将属性添加到exports 指向的对象..

标签: javascript node.js commonjs


【解决方案1】:

即使很久以前就已经回答并接受了问题,但我只想分享我的 2 美分:

你可以想象在你的文件的最开始有类似的东西(只是为了解释):

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

所以无论你做什么,只要记住module.exports 而不是exports 将会在你从其他地方需要模块时从你的模块返回。

所以当你做这样的事情时:

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

您正在向module.exports 指向的对象添加两个函数ab,因此typeof 返回的结果将是object{ a: [Function], b: [Function] }

当然,如果您在此示例中使用 module.exports 而不是 exports,这与您将获得的结果相同。

在这种情况下,您希望您的 module.exports 表现得像一个导出值的容器。然而,如果您只想导出构造函数,那么您应该了解使用 module.exportsexports 的一些知识;(再次记住,当您需要某些东西时将返回 module.exports,而不是 export)。

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

现在typeof 返回结果是'function',您可以要求它并立即调用,如下所示:
var x = require('./file1.js')(); 因为你将返回的结果覆盖为一个函数。

但是,使用 exports 你不能使用类似的东西:

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

因为有了exports,引用不再指向module.exports 指向的对象,所以exportsmodule.exports 之间不再存在关系。在这种情况下,module.exports 仍然指向将返回的空对象 {}

从另一个主题接受的答案也应该有帮助: Does JavaScript pass by reference?

【讨论】:

  • 很好的解释,但我仍然不明白如何从模块中完全省略 module.exports,例如在这个 npm 包中:github.com/tj/consolidate.js/blob/master/lib/consolidate.js
  • @Imray 解释在这里:Does JavaScript pass by reference?exports.a = function(){}; works, exports = function(){} doesn't work
  • oooo 最后这个答案解释了它。基本上,导出是指您可以向其添加属性的对象,但如果您重新分配它以使其发挥作用,那么您将不再将属性附加到该原始对象。现在 export 引用函数,而 module.exports 仍然指向该对象,因为它是返回的内容。可以说 export 基本上已经被垃圾回收了。
  • 那么,使用exports 有什么意义呢?如果只是变量重新分配,为什么不总是使用module.exports?对我来说似乎很困惑。
  • @jedd.ahyoung 通过向exports 添加属性,您可以有效地确保返回“典型”模块导出对象。相反,通过使用module.exports,您可以返回任何您想要的值(原始、数组、函数),而不仅仅是一个对象(这是大多数人期望的格式)。所以module.exports 提供了更多功能,但也可以用于让您的模块导出非典型值(如原语)。相比之下,exports 限制更多,但更安全(只要您简单地向它添加属性并且不重新分配它)。
【解决方案2】:

设置module.exports 允许database_module 函数像required 时的函数一样被调用。简单地设置exports 将不允许该功能 导出,因为节点导出对象 module.exports 引用。以下代码不允许用户调用该函数。

module.js

以下操作无效。

exports = nano = function database_module(cfg) {return;}

如果设置了module.exports,以下将起作用。

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

控制台

var func = require('./module.js');
// the following line will **work** with module.exports
func();

基本上node.js 不会导出exports 当前引用的对象,而是导出exports 最初引用的对象的属性。虽然 Node.js 确实导出对象 module.exports 引用,允许您像调用函数一样调用它。


第二个最不重要的原因

他们同时设置module.exportsexports 以确保exports 没有引用先前导出的对象。通过设置两者,您可以使用 exports 作为速记,并避免以后出现潜在的错误。

使用exports.prop = true 代替module.exports.prop = true 可以节省字符并避免混淆。

【讨论】:

  • @ajostergaard:它恰好是library 的名称,OP 的示例取自。在模块中,它允许作者写nano.version = '3.3'之类的东西,而不是module.exports.version = '3.3',这样读起来更清楚一点。 (注意nano是一个局部变量declared a little before the module exports are set。)
  • @lime - 谢谢 - 我很高兴这在很大程度上无关紧要,因为如果不是,那将意味着我完全误解了一切。 :-| :)
  • 嘿石灰,这是一个很老的答案,但我希望你能澄清一些事情。如果我设置module.exports exports,我的代码还能工作吗?感谢您的帮助!
  • @Asad 是的,如果您设置了module.exports,该函数将正确导出
  • @Liam 感谢您的宝贵回答。更多查询 - 在 server.js 的入口处,module.exports 和 export 的值应该是什么? module.exports 是否应该为 null 并且 export 设置为空对象?这是遗留问题还是有一些有效的用例将 export 和 module.exports 指向两个不同的对象?
【解决方案3】:

基本上,答案在于通过require 语句需要模块时真正发生的情况。假设这是第一次需要该模块。

例如:

var x = require('file1.js');

file1.js 的内容:

module.exports = '123';

执行上述语句时,会创建一个Module 对象。它的构造函数是:

function Module(id, parent) {
    this.id = id;
    this.exports = {};
    this.parent = parent;
    if (parent && parent.children) {
        parent.children.push(this);
    }

    this.filename = null;
    this.loaded = false;
    this.children = [];
}

如您所见,每个模块对象都有一个名为exports 的属性。这是最终作为require 的一部分返回的内容。

require 的下一步是将 file1.js 的内容包装到一个匿名函数中,如下所示:

(function (exports, require, module, __filename, __dirname) { 
    //contents from file1.js
    module.exports = '123;
});

而这个匿名函数的调用方式如下,这里的module指的是前面创建的Module对象。

(function (exports, require, module, __filename, __dirname) { 
    //contents from file1.js
    module.exports = '123;
}) (module.exports,require, module, "path_to_file1.js","directory of the file1.js");

正如我们在函数内部看到的,exports 形式参数指的是module.exports。本质上,它是为模块程序员提供的一种便利。

但是,需要谨慎使用这种便利。在任何情况下,如果尝试将新对象分配给导出,请确保我们这样做。

exports = module.exports = {};

如果我们按照错误的方式进行操作,module.exports 仍将指向作为模块实例的一部分创建的对象。

exports = {};

因此,向上述导出对象添加任何内容都不会影响 module.exports 对象,并且不会作为 require 的一部分导出或返回任何内容。

【讨论】:

  • 在这里迷路了exports = module.exports = {};
  • 我认为这应该是最好的答案,它解释了为什么func() 在@William 的答案中失败!
  • 我看不出在代码的最后一行添加exports = module.exports = app; 有什么好处。似乎module.exports 将被导出,我们将永远不会使用exports,因为它再次位于代码的最后一行。那么,我们为什么不简单地添加module.exports = app;
【解决方案4】:

最初,module.exports=exportsrequire 函数返回 module.exports 所指的对象。

如果我们向对象添加属性,比如exports.a=1,那么module.exports 和exports 仍然 引用同一个对象。所以如果我们调用require并将模块赋值给一个变量,那么这个变量就有一个属性a,它的值为1;

但如果我们覆盖其中一个,例如exports=function(){},那么它们现在是不同:exports 指的是一个新对象,module.exports 指的是原始对象。如果我们需要文件,它不会返回新对象,因为 module.exports 不是引用新对象。

对我来说,我会继续添加新属性,或者将它们都覆盖到一个新对象中。只覆盖一个是不对的。请记住,module.exports 才是真正的老板。

【讨论】:

  • 是的,这实际上是真正的答案。它简洁明了。其他人可能是对的,但充满了花哨的术语,并没有完全专注于这个问题的答案。
  • 这是迄今为止最明确的答案!如果您想为它添加书签,这是精确的链接:stackoverflow.com/questions/7137397/…
【解决方案5】:

exportsmodule.exports 是相同的,除非您在模块中重新分配 exports

考虑它的最简单方法是认为这条线隐含在每个模块的顶部。

var exports = module.exports = {};

如果在您的模块中重新分配exports,那么您在您的模块中重新分配它,它不再等于module.exports。这就是为什么,如果你想导出一个函数,你必须这样做:

module.exports = function() { ... }

如果您只是将function() { ... } 分配给exports,您将重新分配exports 以不再指向module.exports

如果你不想每次都通过module.exports引用你的函数,你可以这样做:

module.exports = exports = function() { ... }

注意module.exports 是最左边的参数。

将属性附加到exports 是不同的,因为您没有重新分配它。这就是为什么它有效

exports.foo = function() { ... }

【讨论】:

    【解决方案6】:

    JavaScript 通过引用的副本传递对象

    这与 JavaScript 中通过引用传递对象的方式存在细微差别。

    exportsmodule.exports 都指向同一个对象。 exports 是一个变量,module.exports 是模块对象的一个​​属性。

    假设我这样写:

    exports = {a:1};
    module.exports = {b:12};
    

    exportsmodule.exports 现在指向不同的对象。修改导出不再修改 module.exports。

    当导入函数检查module.exports 时,它会得到{b:12}

    【讨论】:

    • "JavaScript 通过引用传递" – No.
    【解决方案7】:

    我只是做了一些测试,结果发现,在nodejs的模块代码中,它应该是这样的:

    var module.exports = {};
    var exports = module.exports;
    

    所以:

    1:

    exports = function(){}; // this will not work! as it make the exports to some other pointer
    module.exports = function(){}; // it works! cause finally nodejs make the module.exports to export.
    

    2:

    exports.abc = function(){}; // works!
    exports.efg = function(){}; // works!
    

    3:但是,在这种情况下

    module.exports = function(){}; // from now on we have to using module.exports to attach more stuff to exports.
    module.exports.a = 'value a'; // works
    exports.b = 'value b'; // the b will nerver be seen cause of the first line of code we have do it before (or later)
    

    【讨论】:

    • Lyman,所以module.exports 是节点关闭的“真正交易”,但在某些时候,您需要将所有exports 添加到module.exports,除非您'重新使用exports.namespace(上面的情况2),在这种情况下,这似乎就像Node运行extends(module.exports, exports);exports的所有“命名空间”添加到module.exports对象?换句话说,如果您使用的是exports,那么您可能想要在其上设置属性?
    【解决方案8】:

    这是 Manning 出版物的 node.js in action 一书中关于节点模块的良好描述。
    最终在您的应用程序中导出的是 module.exports。
    exports
    已设置 up 简单地作为对 module.exports 的全局引用,它最初被定义为 可以添加属性的空对象。所以 exports.myFunc 只是简写 对于 module.exports.myFunc

    因此,如果 exports 设置为其他任何值,它会破坏 引用 module.exportsexports 。因为 module.exports 才是真正得到的 导出后,exports 将不再按预期工作——它不引用 模块 .exports 了。如果您想维护该链接,您可以制作 module.exports 再次引用导出如下:

    module.exports = exports = db;
    

    【讨论】:

      【解决方案9】:

      要了解这些差异,您必须首先了解 Node.js 在运行时对每个模块的作用。 Node.js 为每个模块创建一个包装函数:

       (function(exports, require, module, __filename, __dirname) {
      
       })()
      

      注意第一个参数exports是一个空对象,第三个参数module是一个有很多属性的对象,其中一个属性名为exports。这就是exports 的来源和module.exports 的来源。前者是变量对象,后者是module对象的属性。

      在模块内,Node.js 会自动在开头做这件事:module.exports = exports最终返回module.exports

      因此您可以看到,如果您将某个值重新分配给exports,它不会对module.exports 产生任何影响。 (只是因为exports 指向另一个新对象,但module.exports 仍然持有旧的exports

      let exports = {};
      const module = {};
      module.exports = exports;
      
      exports = { a: 1 }
      console.log(module.exports) // {}
      

      但是如果你更新exports的属性,肯定会对module.exports产生影响。因为它们都指向同一个对象。

      let exports = {};
      const module = {};
      module.exports = exports;
      
      exports.a = 1;
      module.exports.b = 2;
      console.log(module.exports) // { a: 1, b: 2 }
      

      还请注意,如果您将另一个值重新分配给 module.exports,那么对于 exports 更新似乎没有意义。 exports 上的每次更新都会被忽略,因为 module.exports 指向另一个对象。

      let exports = {};
      const module = {};
      module.exports = exports;
      
      exports.a = 1;
      module.exports = {
        hello: () => console.log('hello')
      }
      console.log(module.exports) // { hello: () => console.log('hello')}
      

      【讨论】:

        【解决方案10】:

        我经历了一些测试,我认为这可能会对这个主题有所启发......

        app.js:

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

        /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] }"
        

        我什至添加了新文件:

        ./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(){};
        

        我们得到输出“@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(){};
        

        我们得到输出“@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(){};
        

        我们得到输出“@routes { user: [Function: user] }” 如果我们将user.js 更改为{ ThisLoadedLast: [Function: ThisLoadedLast] },我们会得到输出“@routes { ThisLoadedLast: [Function: ThisLoadedLast] }”。


        但是如果我们修改./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(){};
        

        ...我们得到“@routes { fn: { fn: [Function: fn] }, ThisLoadedLast: { ThisLoadedLast: [Function: ThisLoadedLast] } }”

        所以我建议总是在你的模块定义中使用module.exports

        我不完全了解 Node 内部发生了什么,但如果您能更清楚地理解这一点,请发表评论,因为我相信它会有所帮助。

        -- 快乐编码

        【讨论】:

        • 我认为它们是不必要的复杂和混乱。它应该是透明和直观的。
        • 我同意。在某些情况下,它可能对命名空间有用,但通常不会造成或破坏任何东西。
        【解决方案11】:

        这显示了require() 如何以最简单的形式工作,摘自Eloquent JavaScript

        问题 模块不能直接导出导出对象以外的值,例如函数。例如,一个模块可能只想导出它定义的对象类型的构造函数。现在,它不能这样做,因为 require 总是使用它创建的 exports 对象作为导出值。

        解决方案 为模块提供另一个变量module,它是一个具有属性exports 的对象。此属性最初指向由 require 创建的空对象,但可以用另一个值覆盖以导出其他内容。

        function require(name) {
          if (name in require.cache)
            return require.cache[name];
          var code = new Function("exports, module", readFile(name));
          var exports = {}, module = {exports: exports};
          code(exports, module);
          require.cache[name] = module.exports;
          return module.exports;
        }
        require.cache = Object.create(null);
        

        【讨论】:

        • 我不得不在 Node 中重新创建它并测试一些东西,直到我得到,我糟透了。基本上,为模块创建的内部函数甚至从不返回导出对象。所以“exports”对象实际上并没有在模块中重新分配,例如如果您尝试直接编写exports = "this is a string"。该对象仅作为参考存在。这是我认为直到现在我还没有真正理解的行为。
        【解决方案12】:

        这是

        的结果
        console.log("module:");
        console.log(module);
        
        console.log("exports:");
        console.log(exports);
        
        console.log("module.exports:");
        console.log(module.exports);
        

        还有:

        if(module.exports === exports){
            console.log("YES");
        }else{
            console.log("NO");
        }
        
        //YES
        

        注意: CommonJS 规范只允许使用 exports 变量来公开公共成员。因此,命名导出模式是唯一真正与 CommonJS 规范兼容的模式。 module.exports 的使用是 Node.js 提供的一个扩展,用于支持更广泛的模块定义模式。

        【讨论】:

          【解决方案13】:
          var a = {},md={};
          

          //首先exports和module.exports指向同一个空Object

          exp = a;//exports =a;
          md.exp = a;//module.exports = a;
          
          exp.attr = "change";
          
          console.log(md.exp);//{attr:"change"}
          

          //如果你将 exp 指向其他对象,而不是将它的属性指向其他对象。 md.exp 将为空 Object {}

          var a ={},md={};
          exp =a;
          md.exp =a;
          
          exp = function(){ console.log('Do nothing...'); };
          
          console.log(md.exp); //{}
          

          【讨论】:

            【解决方案14】:

            来自docs

            exports 变量在模块的文件级范围内可用,并且在评估模块之前被分配了 module.exports 的值。

            它允许使用快捷方式,因此 module.exports.f = ... 可以更简洁地写为 export.f = .... 但是,请注意,与任何变量一样,如果为导出分配了一个新值,它不再绑定到 module.exports:

            只是一个指向module.exports的变量。

            【讨论】:

              【解决方案15】:

              我发现此链接对回答上述问题很有用。

              http://timnew.me/blog/2012/04/20/exports-vs-module-exports-in-node-js/

              添加到其他帖子节点中的模块系统确实

              var exports = module.exports 
              

              在执行代码之前。所以当你想 export = foo 时,你可能想做 module.exports = exports = foo 但使用 exports.foo = foo 应该没问题

              【讨论】:

              • git 链接已损坏
              • 链接现已修复。
              【解决方案16】:

              “如果您希望模块导出的根是一个函数(例如构造函数),或者如果您想在一个赋值中导出一个完整的对象而不是一次构建一个属性,请将其分配给 module.出口而不是出口。” - http://nodejs.org/api/modules.html

              【讨论】:

                【解决方案17】:

                让我们用两种方式创建一个模块:

                一种方式

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

                第二种方式

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

                这就是 require() 将如何集成模块。

                第一种方式:

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

                第二种方式

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

                【讨论】:

                  【解决方案18】:

                  module.exportsexports 在评估模块之前都指向同一个对象。

                  当您的模块使用require 语句在另一个模块中使用时,您添加到module.exports 对象的任何属性都将可用。 exports 是可用于同一事物的快捷方式。例如:

                  module.exports.add = (a, b) => a+b
                  

                  相当于写:

                  exports.add = (a, b) => a+b
                  

                  所以只要不给exports变量赋值就可以了。当你做这样的事情时:

                  exports = (a, b) => a+b 
                  

                  当您为 exports 分配新值时,它不再引用导出的对象,因此将保持在您的模块本地。

                  如果您打算为 module.exports 分配一个新值,而不是向可用的初始对象添加新属性,您可能应该考虑如下所示:

                  module.exports = exports = (a, b) => a+b
                  

                  Node.js website has a very good explanation of this.

                  【讨论】:

                    【解决方案19】:

                    1.exports -> 用作单例实用程序
                    2. module-exports -> 用作逻辑对象,例如服务,模型等

                    【讨论】:

                      【解决方案20】:

                      为什么这里都用到了

                      我相信他们只是想清楚module.exportsexportsnano 指向同一个函数 - 允许您使用任一变量来调用文件中的函数。 nano 为函数的作用提供了一些上下文。

                      exports 不会被导出(只有module.exports 会),那么为什么还要覆盖它呢?

                      冗长权衡限制了未来出现错误的风险,例如在文件中使用exports 而不是module.exports。它还澄清module.exportsexports 实际上指向相同的值。


                      module.exportsexports

                      只要您不重新分配module.exportsexports(而是将值添加到它们都引用的对象),您就不会遇到任何问题并且可以安全地使用exports 更简洁.

                      当分配给非对象时,它们现在指向不同的地方,这可能会造成混淆,除非您有意将 module.exports 指定为特定的东西(例如函数)。

                      exports 设置为非对象没有多大意义,因为您必须在最后设置module.exports = exports 才能在其他文件中使用它。

                      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
                      

                      为什么要将module.exports 分配给函数?

                      更简洁!比较第二个例子有多短:

                      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

                      【讨论】:

                        【解决方案21】:

                        您创建的每个文件都是一个模块。模块是一个对象。它具有名为exports : {} 的属性,默认为空对象。

                        您可以创建函数/中间件并添加到这个空的导出对象,例如 exports.findById() => { ... } 然后 require 在您的应用中的任何位置并使用...

                        controllers/user.js

                        exports.findById = () => {
                            //  do something
                        }
                        

                        需要在 routes.js 中使用:

                        const {findyId} = './controllers/user'
                        

                        【讨论】:

                          【解决方案22】:

                          在 node js 中,module.js 文件用于运行 module.load 系统。每次 node 执行文件时,它都会将你的 js 文件内容包装如下

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

                          因为这个包装在你的 js 源代码中,你可以访问 export、require、module 等。 使用这种方法是因为没有其他方法可以将写入 js 文件的功能写入另一个文件。

                          然后节点使用 c++ 执行这个包装函数。那时,传入此函数的导出对象将被填充。

                          你可以在这个函数里面看到exports和module的参数。 实际上,exports 是模块构造函数的公共成员。

                          看下面的代码

                          将此代码复制到 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();
                          

                          将此代码复制到 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');}
                          

                          现在使用节点运行

                          这是输出

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

                          导出为 [object Object]

                          foo 的 object.keys: 名称是 function (){console.log('function to module exports')} 模块导出函数

                          现在删除 a.js 中的注释行并注释该行上方的行 并删除 b.js 的最后一行并运行。

                          在 javascript 世界中,您不能重新分配作为参数传递的对象,但是当该函数的对象设置为另一个函数的参数时,您可以更改函数的公共成员

                          记得

                          使用 module.exports 并且仅当您想在使用 require 关键字时获取函数时才使用。 在上面的例子中,我们 var foo = require(a.js);你可以看到我们可以把 foo 作为一个函数来调用;

                          这是节点文档的解释方式 “导出对象是由模块系统创建的。有时这是不可接受的,许多人希望他们的模块成为某个类的实例。为此,将所需的导出对象分配给 module.exports。”

                          【讨论】:

                            【解决方案23】:
                            1. module.exportsexports 都指向同一个 function database_module(cfg) {...}

                              1| var a, b;
                              2| a = b = function() { console.log("Old"); };
                              3|     b = function() { console.log("New"); };
                              4|
                              5| a(); // "Old"
                              6| b(); // "New"
                              

                              你可以把第3行的b改成a,输出是相反的。结论是:

                              ab 是独立的。

                            2. 所以module.exports = exports = nano = function database_module(cfg) {...} 等价于:

                              var f = function database_module(cfg) {...};
                              module.exports = f;
                              exports = f;
                              

                              假设上面是module.js,这是foo.js所需要的。 module.exports = exports = nano = function database_module(cfg) {...} 的好处现在很明显:

                              • foo.js 中,因为module.exportsrequire('./module.js')

                                var output = require('./modules.js')();
                                
                              • moduls.js:您可以使用exports 代替module.exports

                            所以,如果 exportsmodule.exports 都指向同一个东西,你会很高兴。

                            【讨论】:

                              【解决方案24】:
                              • exports:它是对 module.exports 对象的引用
                              • exportsmodule.exports 都指向同一个对象 直到我们改变 exports 对象的引用

                              示例:

                              1. 如果exports.a = 10,那么module.exports.a = 10

                              2. 如果我们在代码中明确地重新分配导出对象,例如 export = {} 现在它失去了对 module.exports 的引用

                              【讨论】:

                                猜你喜欢
                                • 1970-01-01
                                • 1970-01-01
                                • 2013-08-08
                                • 2017-03-10
                                • 2016-12-09
                                • 1970-01-01
                                • 2012-08-31
                                相关资源
                                最近更新 更多