Expressjs JavaScript基础:exports = module.exports = createApplication;

5

我不知道这个模式被称为什么,如果我知道我会直接查找。

主要是,这是如何工作的?(此代码取自Express.js)

exports = module.exports = createApplication;

我之前见过类似的模式,其中存在这种类型的引用变量链,例如:

x = y = z

我了解exports和module.exports的区别,但看到上面的模式时,我对它是如何工作产生了疑问。
一般来说,我遵循一个经验法则,即“module.exports”是真正的内容,“exports”只是它的助手,更多信息请参考这里
如果不修改module.exports,那么模块模式是否就像这样?
exports = module.exports = {};

示例:

exports.name = 'hello' 

结果为

exports = module.exports = {name: 'hello'}

当更改exports上的引用时会发生什么?
exports = {name: 'bob'}

现在,当您添加到exports时,它将引用`{name: 'bob'}`,并不再与module.exports有任何联系?

最近我通过一个NodeJS应用程序(你也可以尝试使用Node Inspector)进行了调试,发现每个模块都被自动包装了一个函数。它的签名是function(module, exports, /* two other */) { /* the actual module code */ }。我怀疑exports只是module.exports的简写,因为我遇到了这两种赋值方式。所以,我认为使用哪个左侧并没有区别,而且exports = module.exports是多余的。 - try-catch-finally
1个回答

5
你的直觉是正确的。我将从底层开始工作:

Node.js包装器

在运行任何文件之前,Node.js会在一个立即调用函数表达式(IIFE)包装整个脚本
(function (exports, require, module, __filename, __dirname) {
    // ...script goes here...
});

这是如何将“module”和“exports”变量引入作用域的方法;它们只是函数参数,并没有什么特别之处。
使用“exports”
Node.js文档中关于“module.exports”和“exports”别名的介绍非常有帮助。首先,“module.exports”和“exports”变量都指向由模块系统创建的相同空对象。
如果一个模块只需要导出一个简单的JavaScript对象并设置一些属性,“exports”就足够了。
exports.get = function(key) {
    // ...
};

exports.set = function(key, value) {
    // ...
};

当代码使用require()导入此模块时,结果将类似于:
{
    get: [Function],
    set: [Function]
}

替换module.exports

然而,Express将构造函数createApplication作为根值导出。要导出函数本身,而不仅仅是将其分配给导出对象的属性,必须首先完全替换导出的对象:

module.exports = createApplication;

现在,exports 没有更新并且仍然指向旧对象,而 module.exports 是对 createApplication 的引用。但是 如果您继续阅读, 您会注意到Express除构造函数之外还导出了其他几个属性。虽然将这些分配给 module.exports 的新值的属性足以,但重新分配 exports 使其再次成为 module.exports 的别名,然后将这些属性分配给 exports,这相当于将它们分配给 module.exports

因此,这些示例在功能上是等效的:
module.exports = createApplication;

function createApplication() {
    // ...
}

module.exports.application = proto;
module.exports.request = req;
module.exports.response = res;

但这个更简洁:
exports = module.exports = createApplication;

function createApplication() {
    // ...
}

exports.application = proto;
exports.request = req;
exports.response = res;

无论哪种方式,结果都是一样的,在根目录下有一个名为createApplication的函数,其属性可供使用:
{
    [Function: createApplication]
    application: [Object],
    request: [Object],
    response: [Object],
    // ...a few other properties...
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接