Node.js中module.exports和exports

Node.js中,导出一个对象可以用exports,也可以用module.exports,但是这两者是有些区别的。
先看一个例子:

1
2
3
4
5
6
7
8
9
10
11
//snippet-1:

// foo1.js
exports.foo = "foo1";

// foo2.js
module.exports.foo = "foo2";

// bar.js
console.log(require('./foo1').foo); // Output: foo1
console.log(require('./foo2').foo); // Output: foo2

可以看到,这种情况下,module.exportsexports的效果是一样的。再看另外一个例子:

1
2
3
4
5
6
7
8
9
10
11
//snippet-2:

// foo1.js
exports = "foo1";

// foo2.js
module.exports = "foo2";

// bar.js
console.log(require('./foo1')); // Output: {}
console.log(require('./foo2')); // Output: foo2

在这个代码段中,foo1.js并没有导出想要的对象,为什么呢?
Node.js中,exportsmodule.exports的一个引用,Node.js的官方文档中,给出了一个require()的简单的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function require(/* ... */) {
const module = { exports: {} };
((module, exports) => {
// Module code here. In this example, define a function.
function someFunc() {}
exports = someFunc;
// At this point, exports is no longer a shortcut to module.exports, and
// this module will still export an empty default object.
module.exports = someFunc;
// At this point, the module will now export someFunc, instead of the
// default object.
})(module, module.exports);
return module.exports;
}

这就不难理解了,如果这样导出对象:

1
exports = 'xxx';

其实是修改了exports的指向:不再是之前的module.export的指向;而在Node.js中是通过module.exports导出对象的,
所以在snippets-2中,并不能正确的导出结果。