【问题标题】:module.exports colliding / being overwritten in node.js applicationmodule.exports 冲突/在 node.js 应用程序中被覆盖
【发布时间】:2012-08-24 18:59:04
【问题描述】:

我认为我严重误解了如何使用 module.exports。似乎每个模块都在覆盖最后一个吐出的内容。

app.js

var express = require("express")
    , app = express()
    , routes = require('routes')
    , server = app.listen(1337, "0.0.0.0")
    , io = require('socket.io').listen(server)
    , redis = require("redis")
    , client = redis.createClient();

var moduleA = require("./moduleA")(io, client);(需要通过socket.io和redis客户端)

var moduleB = require("./moduleB")(io, client);(相同)

moduleA.js

module.exports = function(io, client){ 
    this.test = 'foo';
    return this;
};

moduleB.js

module.exports = function(io, client){ 
    this.test = 'bar';
    return this;
};

返回 app.js

console.log(moduleB.test);打印“条”

console.log(moduleA.test);打印“bar”

有人可以解释我做错了什么吗?我想不出任何其他方法来做到这一点,因为 exports 助手 (?) 本身似乎不接受参数。

【问题讨论】:

    标签: javascript node.js express node-modules


    【解决方案1】:

    您正在导出一个构造函数。你需要构建它,而不是调用它。

    改变

    var moduleA = require("./moduleA")(io, client);
    

    var moduleA = new (require("./moduleA"))(io, client);
    

    或(为了清楚起见)

    var ModuleA = require("./moduleA");
    var a = new ModuleA(io, client);
    

    您所看到的是在草率模式下将构造函数作为函数调用时的常见行为:this 引用全局对象。所以当然从两个位置修改全局对象会互相覆盖,返回this只会返回全局对象。您可以自己测试:使用您当前的代码,

    moduleA === moduleB === this === global
    

    防止自己再次像这样在脚上开枪的一种方法是使用严格模式而不是马虎模式。为此,请添加行

    "use strict";
    

    在您编写的每个模块的顶部(在任何其他代码之前)。在严格模式下,没有new 调用的构造函数的thisundefined,因此您会得到一个更早且更容易理解的错误。

    严格模式有很多这样的好处;有关概述,请参阅[1][2][3]


    另一种解决方案是完全停止使用构造函数,而是使用工厂函数。这看起来像:

    module.exports = function (io, client) {
        var result = {};
        result.test = "foo";
        return result;
    };
    

    你似乎正在尝试做这样的事情,因为你 return this 即使在构造函数中这样做是完全没有必要的。您可以停止使用 this 并使用您控制下的实际对象,而不是根据您的函数是否被调用或构造而改变语义的对象。

    【讨论】:

    • +1;在调用this.test = 之前添加console.log(this) 以查看this 实际上是全局范围。
    • 非常感谢!用你最后的建议避免this snafu 效果很好。我刚刚使用了var exp = {}; exp.test = 'foo'; return exp;,我仍然不确定我是否理解var x = require('./x')var x = new require('./x') 之间的区别——这两种方法似乎都没有不同的效果。
    • @Greg:我的原始帖子中有一个错字---我忘记了(require("./moduleA")) 周围的括号。至于区别是什么,这是使用new(构造它)调用函数与不调用它(调用它)之间的通常区别。即构造函数创建一个新的空对象并将其作为this 传递给构造函数,然后隐式返回this 的值。
    • 不同的是因为x是导出函数,var x = new require('./x')是实例化require返回的函数。通过使用var x = require('./x'),您实际上并没有创建对象,而是将导出的函数分配给 x。然后你需要var derp = new x(); 来实例化对象。
    • 这就是简单调用函数和调用该函数作为构造函数的区别。我建议您阅读 JavaScript 构造函数;像 Crockford 的 JavaScript: The Good Parts 之类的东西会是一个很好的来源,尽管并不是每个人都像 Crockford 一样对构造函数的使用感到失望。
    猜你喜欢
    • 1970-01-01
    • 2013-03-12
    • 2017-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多