Node.js 的 exports 和 module.exports 两者很容易给新手造成疑惑。这里希望能讲清楚它们的异同。
相同之处
exports 和 module.exports 并不是全局变量,而只是对各自的 module 可见。
它们指向同一个对象,其缺省初始值为空 {}。
如果 exports 和 module.exports 没有被重新赋值,这个对象就是将要输出的对象。
不同之处
module 是对当前模块的一个引用。真正输出的是 module.exports。
所以对 exports 直接赋值没有作用。而对 module.exports 直接赋值后,module.exports 就指向新的对象了,这个新的对象成为将要被输出的对象。
详细说明
exports 和 module.exports 指向的是同一个对象,所以给他们任何一个添加属性或方法,另外一个都会接收到变化,因为他们指向的是同一个对象。例如:
exports.afunc = function(){};
module.exports.name = "Wang";
console.log(exports);
console.log(module.exports);
后面两条语句的输出都是: <code> { afunc: [Function], name: ‘Wang’ } </code> 。
但是如果是对其中任何一个直接赋值,就会切断对最初对象的引用。
- exports
例如给 exports 直接赋值,就切断了 exports 对之前其和 module.exports 一同指向的对象的引用,但是由于真正输出的是 module.exports 指向的对象,所以对 exports 赋值无效,比如在 ep.js 输入:
exports.name = "Wang";
var afunc = function(){};
exports = afunc; //注意对 require 无效
console.log(exports); //内部有效,输出 [Function]
在另外一个 me.js 输入:
var ep = require('./ep');
console.log(ep);//输出 {name: 'Wang'},不是 [Function]
要让 exports 输出,可以在 ep.js 加上
module.exports = exports;
两者的 reference 关系再次建立。这样输出都是 [Function] 。
- module.exports
如果给 module.exports 直接赋值,也切断了 exports 的引用,同样道理,因为真正输出的是 module.exports 指向的对象,所以新赋给 module.exports 的对象将被输出。例如把 ep.js 改为:
exports.name = "Li";
console.log(exports); //{name: 'Li'}
console.log(module.exports);//一样 {name: 'Li'}
module.exports = "Zhou";
console.log(exports); //还是 {name: 'Li'}
console.log(module.exports);//变为 Zhou
再次运行 me.js,输出 <code> Zhou </code>, 覆盖了之前的对象.
总结
真正输出总是 module.exports。如果两者同时出现或被修改,只有 module.exports 返回,exports 被忽略。