CommonJs模块系统中“module.exports”和“exports”的区别
在这个页面上( http://docs.nodejitsu.com/articles/getting-started/what-is-require ),它指出:“如果你想把exports对象设置为一个函数或一个新的对象,你必须使用module.exports对象“。
我的问题是为什么。
// right module.exports = function () { console.log("hello world") } // wrong exports = function () { console.log("hello world") }
我console.logged结果( result=require(example.js)
),第一个是[Function]
第二个是{}
。
你能解释一下它背后的原因吗? 我在这里阅读这篇文章: module.exports vs在Node.js中导出 。 这是有帮助的,但没有解释为什么这样devise的原因。 如果直接返回出口的参考资料,会出现问题吗?
module
是一个带有exports
属性的普通JavaScript对象。 exports
是一个普通的JavaScriptvariables,恰好被设置为module.exports
。 在文件的最后,node.js基本上将module.exports
返回给require
函数。 在Node中查看JS文件的简单方法可能是这样的:
var module = { exports: {} }; var exports = module.exports; // your code return module.exports;
如果你设置一个exports
属性,比如exports.a = 9;
,也会设置module.exports.a
,因为对象是作为JavaScript中的引用传递的,这意味着如果你为同一个对象设置多个variables,它们都是同一个对象; 那么exports
和module.exports
是同一个对象。
但是,如果将exports
设置为新的内容,则不再将其设置为module.exports
,因此exports
和module.exports
不再是同一个对象。
蕾妮的回答很好解释。 除了用一个例子来回答:
节点为你的文件做了很多事情,其中一个重要的事情是包装你的文件。 在nodejs内部返回源代码“module.exports”。 让我们退后一步,了解包装。 假设你有
greet.js
var greet = function () { console.log('Hello World'); }; module.exports = greet;
上面的代码被封装为nodejs源代码中的IIFE(即时调用函数expression式),如下所示:
(function (exports, require, module, __filename, __dirname) { //add by node var greet = function () { console.log('Hello World'); }; module.exports = greet; }).apply(); //add by node return module.exports; //add by node
并调用上述函数(.apply())并返回module.exports。 此时module.exports和exports指向相同的引用。
现在,想象你重写greet.js为
exports = function () { console.log('Hello World'); }; console.log(exports); console.log(module.exports);
输出将是
[Function] {}
原因是:module.exports是一个空的对象。 我们没有设置任何东西到module.exports而是我们设置exports = function()…..在新的greet.js。 所以,module.exports是空的。
技术上出口和module.exports应该指向相同的参考(即正确!!)。 但是,在将function()分配给导出时,我们使用“=”,这会在内存中创build另一个对象。 所以,module.exports和exports会产生不同的结果。 说到出口,我们不能重写它。
现在,想象你重写(这称为突变)greet.js(指Renee答案)为
exports.a = function() { console.log("Hello"); } console.log(exports); console.log(module.exports);
输出将是
{ a: [Function] } { a: [Function] }
正如你所看到的module.exports和exports是指向相同的引用,这是一个函数。 如果你在导出上设置属性,那么它将被设置在module.exports上,因为在JS中,对象是通过引用传递的。
结论总是使用module.exports来避免混淆。 希望这可以帮助。 快乐编码:)
另外,有一件事可能有助于理解:
math.js
this.add = function (a, b) { return a + b; };
client.js
var math = require('./math'); console.log(math.add(2,2); // 4;
伟大的,在这种情况下:
console.log(this === module.exports); // true console.log(this === exports); // true console.log(module.exports === exports); // true
因此,默认情况下,“this”实际上等于module.exports。
但是,如果您将您的实施更改为:
math.js
var add = function (a, b) { return a + b; }; module.exports = { add: add };
在这种情况下,它会正常工作,但是,“this”不等于module.exports,因为创build了一个新的对象。
console.log(this === module.exports); // false console.log(this === exports); // true console.log(module.exports === exports); // false
而现在,require的返回值是module.exports中定义的内容,而不是this或者exports。
另一种做法是:
math.js
module.exports.add = function (a, b) { return a + b; };
要么:
math.js
exports.add = function (a, b) { return a + b; };
Rene关于exports
和module.exports
之间的关系的回答是非常明确的,这些都是关于javascript引用的。 只是想补充一点:
我们在许多节点模块中看到这一点:
var app = exports = module.exports = {};
这将确保即使我们改变了module.exports,我们仍然可以通过使这两个variables指向同一个对象来使用导出。