如何在浏览器中命名模块,但不在节​​点中命名

时间:2014-01-23 14:03:07

标签: node.js

我已经看到了许多检测全局对象(module.export / window)的自调用模式的例子 - 但是我不知道如何使用这种模式进行命名空间并且仍然以相同的方式在节点中工作。

(function(exports) {
    'use strict';

    // how do i do something like this and have it work in node as well
    // exports Namespace.Models.HelloWorld = function () {}

    exports.say = function() {
        return 'hello world';
    };
}(typeof exports === 'undefined' ? this.helloworld = {} : exports));

2 个答案:

答案 0 :(得分:2)

在查看代码后,我认为你的代码应该可以正常工作。你想要的是命名所有代码,以便它不会污染全局命名空间吗?因此,您需要的是全局命名空间中的单个对象,然后将所有代码放在。

之下
  

注意:如果您不知道,浏览器中的全局命名空间为window

例如,JQuery只创建两个全局对象:jQuery$。使用JQuery所做的一切只涉及那两个全局对象。 JQuery甚至具有禁用美元符号的兼容模式,因此您只有jQuery对象。即使被禁用,人们用来获取美元符号的模式也是这样做的:

(function ($) {
    // Do stuff with $
})(jQuery);

这是一个自调用函数,它将jQuery对象传递给自身,然后成为$参数。这样你就可以获得美元符号的便利而不会用另一个属性堵塞全局window对象。在您的代码(this.helloWorld)中,this关键字引用全局命名空间(除非您的代码包含在另一个函数或其他内容中,并且您没有发布它)。你所做的是在名为window的{​​{1}}对象(全局命名空间)上创建一个属性,你将它设置为一个空对象,然后将其传入。但是你只能在{{helloWorld 1}}是exports。这是确定您是否在节点中的部分。如果您在浏览器中,undefined将只是exports,因为undefined仅在节点模块中可用(只是不要将exports属性添加到全局命名空间中浏览器,哈哈)。

  

注意:Node没有应用程序范围的“全局”命名空间,默认情况下会将其放入。节点中的所有内容都限定在模块级别。因此,即使您在模块的第一行定义变量,您仍然可以在另一个模块的第一行定义完全相同的变量,它们不会相互冲突。但是,节点中的exports对象确实是全局的,您可以从任何模块访问其属性。我不鼓励你使用global对象,就像,永远。如果您需要使用该对象,那么您应该重新考虑您的应用程序结构。

您在节点中附加到global的内容对于需要它的任何其他模块都可用。

exports

然后......

// helloWorld.js
exports.message = "Hello, world!";

在浏览器中,您希望通过将单个唯一命名对象附加到// main.js var helloWorld = require('./helloWorld.js'); // Now all the properties are available on the variable `helloWorld`. console.log(helloWorld.message); // Prints "Hello, world!" to the console. 来执行类似操作,然后使用您的脚本的任何人都应通过该“命名空间”访问所有功能。最后我们有了这个:

window

如果// helloWorld.js (function (myNamespace) { myNamespace.message = "Hello, world!"; })(typeof exports === 'undefined' ? this.helloWorld = {} : exports) 不存在,请将exports添加到helloWorld(在全局范围内引用this,就像在此示例中一样)并将其传递给window 。如果存在exports ,则将其传入。现在,在函数内部,我们可以将属性和方法附加到myNamespace,并根据环境将它们附加到window.helloWorldexports

我可以将上面的helloWorld.js文件添加到我的节点应用程序中并像这样使用它:

// nodeScript.js
var helloWorld = require('./helloWorld.js');
console.log(helloWorld.message);

或者我可以将上述helloWorld.js文件添加到我的网络应用中。您的页面可能如下所示:

// index.html
<html>
    <head>
        <title>My Site</title>
        <script src="helloWorld.js" />
        <script src="clientScript.js" />
    </head>
    <body>
        <div id="messageBox"></div>
    </body>
</html>

您的脚本可能如下所示:

// clientScript.js
document.getElementById('messageBox').innerHTML = helloWorld.message;

上面的页面最后会出现“Hello,world!”在div内,因为它从我们模块的公开属性中读取消息:)

希望能够解决问题。很抱歉首先使用browserify跳转,而不是直接回答原始问题。我强烈推荐浏览器:)

答案 1 :(得分:1)

您需要browserify。以节点样式编写模块,然后让browserify将它们转换为适当的客户端脚本:)

来自browserify主页:

使用node.js-style编写浏览器代码需要:

// main.js

var foo = require('./foo');
var gamma = require('gamma');

var n = gamma(foo(5) * 3);
var txt = document.createTextNode(n);
document.body.appendChild(txt);

通过分配到module.exports或exports:

来导出功能
// foo.js

module.exports = function (n) { return n * 11 }

使用npm安装模块:

npm install gamma

现在使用browserify命令递归地将从main.js开始的所有必需模块捆绑到一个文件中:

browserify main.js -o bundle.js

Browserify解析AST require()次调用,以遍历项目的整个依赖关系图。

将单个<script>标记放入您的HTML,然后您就完成了!

<script src="bundle.js"></script>

编写像这样的客户端脚本不仅有趣,而且浏览器会将它们捆绑在一起,形成一个漂亮而整洁的缩小的单个脚本文件:D