【问题标题】:Namespaces in node.js with requirenode.js 中带有 require 的命名空间
【发布时间】:2012-07-21 01:43:15
【问题描述】:

我正在通过个人项目四处玩耍并学习誓言。这是一个小型客户端库,在 vows 中完成了测试。因此,我必须构建和测试这样编写的文件:

(function(exports) { 
    var module = export.module = { "version":"0.0.1" }; 
    //more stuff
})(this);

在我的测试中(基于science.js、d3 等)需要这样的模块:

require("../module");

我在尝试运行测试时继续收到“模块未定义错误”,所以我去了一个 repl 并运行:

require("../module")

它返回了:

{ module: { version: "0.0.1" } }

我意识到我可以这样做:

var module = require("../module").module;

但我觉得这样做会造成问题,特别是因为我基于这个项目的库是以我描述的格式来做的。

我希望我的项目的行为类似于我所基于的项目,其中:

require("../module");

在这个命名空间中创建一个变量:

module.version; //is valid.

我在各种库中都看到了这一点,我正在遵循 T 的格式和思考过程,但我相信我可能遗漏了一些我不知道的 require 行为。

【问题讨论】:

标签: node.js require vows


【解决方案1】:

以这种方式创建它没有问题。模块定义了它们在 module.exports 对象中返回的内容。顺便说一句,您实际上并不需要自执行函数 (SEF),没有像浏览器中那样的全局泄漏 :-)

示例

module1.js:

module.exports = {
    module: { 'version': '0.1.1' }
};

main.js:

var module1 = require( './module1.js' );
// module1 has what is exported in module1.js

了解了它的工作原理后,如果您愿意,可以立即轻松导出版本号:

module1.js:

module.exports = '0.1.1';

main.js:

var module1 = require( './module1.js' );
console.log( module1 === '0.1.1' ); // true

或者如果你想要一些逻辑,你可以像这样轻松地扩展你的 module1.js 文件:

module.exports = ( function() {
    // some code
    return version;
} () ); // note the self executing part :-)
// since it's self executed, the exported part
// is what's returned in the SEF

或者,正如许多模块所做的那样,如果您想导出一些实用功能(并使其他功能保持“私有”),您可以这样做:

module.exports = {
    func1: function() {
        return someFunc();
    },

    func2: function() {},

    prop: '1.0.0'
};

// This function is local to this file, it's not exported
function someFunc() {
}

所以,在 main.js 中:

var module1 = require( './module1.js' );
module1.func1(); // works
module1.func2(); // works
module1.prop; // "1.0.0"
module1.someFunc(); // Reference error, the function doesn't exist

你的特殊情况

关于你的特殊情况,我不建议像他们那样做。

如果你看这里:https://github.com/jasondavies/science.js/blob/master/science.v1.js

您看到他们没有使用var 关键字。因此,他们正在创建一个全局变量

这就是为什么他们可以在require 定义全局变量的模块后访问它。

顺便说一句,exports 参数在他们的情况下是无用的。这甚至会产生误导,因为它实际上是 global 对象(相当于浏览器中的 window),而不是 module.exports 对象(函数中的 this 是全局对象,如果是严格模式,它将是 undefined已启用)。

结论

不要像他们那样做,这是个坏主意。全局变量是个坏主意,最好使用 node 的理念,并将所需的模块存储在一个变量中,以便重复使用。

如果你想拥有一个可以在客户端使用并在 node.js 中测试的对象,这里有一个方法:

你的Module.js:

// Use either node's export or the global object in browsers
var global = module ? module.exports : window.yourModule;

( function( exports ) {
    var yourModule = {};
    // do some stuff
    exports = yourModule;
} ( global ) );

为了避免创建global 变量,您可以将其缩短为:

( function( exports ) {
    var yourModule = {};
    // do some stuff
    exports = yourModule;
} ( module ? module.exports : window.yourModule ) );

这样,你可以在客户端这样使用它:

yourModule.someMethod(); // global object, "namespace"

在服务器端:

var yourModule = require( '../yourModule.js' );
yourModule.someMethod(); // local variable :-)

仅供参考,.. 表示“父目录”。这是获取模块的相对路径。如果文件在同一目录中,您将使用.

【讨论】:

  • 感谢 Florian,这解决了 Node 如何处理 require 和模块命名空间的许多问题。
  • 虽然,这是我正在创建的客户端库,并通过节点对它进行了单元测试。话虽这么说,我认为 SEF 是必需的,但是,当我包含 SEF 时,它使 require("../module) return {module:{"stuff":"value" }} 所以,我包装了一个SEF 带有节点自己的管理器来处理命名空间问题,因此我的模块似乎变得相对无用,我基于以下测试方法:science.js、d3.js 和 dc.js。而不是为导出设置变量:var d3 = require("d3"); 在它所做的所有测试中: require("d3"); 并直接调用 d3。
  • 我不知道为什么会发生这种行为,尽管它似乎非常适合使用 node.js 构建、测试和维护客户端库。我不知道发生了什么,如果你能看一下,我将非常感激。如果没有,非常感谢您肯定清理了我在工作和创建服务器端模块时遇到的一些问题。
  • 如果您喜欢这个答案,请点赞! :) 我不明白你在评论中的意思。如果您觉得需要扩展您的问题,请随时编辑您的问题。
  • @MilesMcCrocklin 我编辑了我的答案,在最后添加了关于你的特殊情况的解释:)
猜你喜欢
  • 1970-01-01
  • 2021-04-04
  • 1970-01-01
  • 2021-06-05
  • 1970-01-01
  • 1970-01-01
  • 2013-08-21
  • 2019-07-01
  • 2012-11-22
相关资源
最近更新 更多