我在Node.js模块中找到了以下契约:
module.exports = exports = nano = function database_module(cfg) {...}
我想知道module.exports和exports之间有什么区别,为什么在这里使用它们。
我在Node.js模块中找到了以下契约:
module.exports = exports = nano = function database_module(cfg) {...}
我想知道module.exports和exports之间有什么区别,为什么在这里使用它们。
当前回答
让我们用两种方式创建一个模块:
单向
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;
}
其他回答
我通过了一些测试,我认为这可能会对这个问题有所启发。。。
应用.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:TThisLoadedlast]}”。
但如果我们修改/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内部的情况,但如果您能理解这一点,请发表评论,因为我相信这会有所帮助。
--快乐的编码
以下是
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提供的扩展,以支持更广泛的模块定义模式。
要了解这些差异,您必须首先了解Node.js在运行时对每个模块做了什么。Node.js为每个模块创建一个包装函数:
(function(exports, require, module, __filename, __dirname) {
})()
注意,第一个param导出是一个空对象,第三个param模块是一个具有许多财产的对象,其中一个财产名为exports。这是导出的来源和module.exports的来源。前者是变量对象,后者是模块对象的属性。
在模块中,Node.js在开始时自动执行以下操作:module.exports=exports,并最终返回module.exports。
因此,您可以看到,如果您为导出重新分配一些值,那么它不会对module.exports产生任何影响
let exports = {};
const module = {};
module.exports = exports;
exports = { a: 1 }
console.log(module.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,那么对于导出更新来说似乎没有意义。由于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')}
module.export和exports都指向同一个对象,然后对模块求值。
使用require语句在另一个模块中使用模块时,添加到module.exports对象的任何属性都将可用。导出是一种快捷方式,可用于相同的事情。例如:
module.exports.add = (a, b) => a+b
相当于写:
exports.add = (a, b) => a+b
因此,只要不为导出变量分配新值,就可以了。当你这样做时:
exports = (a, b) => a+b
当您为导出分配新值时,它不再引用导出的对象,因此将保持模块的本地状态。
如果您计划为module.exports分配一个新值,而不是向可用的初始对象添加新的财产,您可能应该考虑如下所示:
module.exports = exports = (a, b) => a+b
Node.js网站对此有很好的解释。
JavaScript通过引用的副本传递对象
这与JavaScript中通过引用传递对象的方式有细微差别。
exports和module.exports都指向同一个对象。exports是变量,module.exports是模块对象的属性。
假设我写了这样的东西:
exports = {a:1};
module.exports = {b:12};
exports和module.exports现在指向不同的对象。修改导出不再修改module.exports。
当import函数检查module.exports时,它得到{b:12}