dgh*_*dgh 10 javascript node.js
我正在编写客户端代码,并希望编写多个可以交互的模块化JS文件,同时防止全局命名空间污染.
的index.html
<script src="util.js"></script>
<script src="index.js"></script>
Run Code Online (Sandbox Code Playgroud)
util.js中
(function() {
var helper() {
// Performs some useful utility operation
}
});
Run Code Online (Sandbox Code Playgroud)
index.js
(function () {
console.log("Loaded index.js script");
helper();
console.log("Done with execution.");
})
Run Code Online (Sandbox Code Playgroud)
此代码很好地将实用程序函数保存在单独的文件中,并且不会污染全局命名空间.但是,不会执行辅助实用程序函数,因为'helper'存在于单独的匿名函数名称空间中.
一种替代方法涉及将所有JS代码放在一个文件中或在全局命名空间中使用单个变量,如下所示:
var util_ns = {
helper: function() {
// Performs some useful utility operation.
},
etc.
}
Run Code Online (Sandbox Code Playgroud)
这两种方法在模块化和干净的命名空间方面都有缺点.
我习惯在Node.js中工作(服务器端),我可以在另一个内部"需要"一个Javascript文件,有效地将util.js绑定注入index.js命名空间.
我想在这里做类似的事情(但是客户端),允许代码在单独的模块化文件中编写,而不在全局命名空间中创建任何变量,同时允许访问其他模块(例如实用程序模块).
这是否可以通过简单的方式实现(没有库等)?
如果没有,在使客户端JS的行为更像Node和npm的领域,我知道requireJS,browserify,AMD和commonJS标准化尝试的存在.但是,我不确定每个的优缺点和实际用法.
Eug*_*nov 17
我强烈建议你继续使用RequireJS.
模块支持方法(不需要/依赖):
// moduleA.js
var MyApplication = (function(app) {
app.util = app.util || {};
app.util.hypotenuse = function(a, b) {
return Math.sqrt(a * a + b * b);
};
return app;
})(MyApplication || {});
// ----------
// moduleB.js
var MyApplication = (function(app) {
app.util = app.util || {};
app.util.area = function(a, b) {
return a * b / 2;
};
return app;
})(MyApplication || {});
// ----------
// index.js - here you have to include both moduleA and moduleB manually
// or write some loader
var a = 3,
b = 4;
console.log('Hypotenuse: ', MyApplication.util.hypotenuse(a, b));
console.log('Area: ', MyApplication.util.area(a, b));
Run Code Online (Sandbox Code Playgroud)
在这里,您只创建一个全局变量(命名空间)MyApplication,所有其他内容都"嵌套"到其中.
小提琴 - http://jsfiddle.net/f0t0n/hmbb7/
**我之前在项目中使用过的另一种方法 - https://gist.github.com/4133310 但是无论如何我在开始使用RequireJS时抛弃了所有这些东西.*
您应该查看browserify,它将模块化JavaScript项目处理为单个文件.您可以require像在节点中一样使用它.
它甚至给出了一堆node.js libs url,http和crypto.
附加:在我看来,浏览器的专业是它只是使用并且不需要自己的代码 - 您甚至可以使用已经编写的node.js代码.根本没有必要的样板代码或代码更改,它与node.js一样符合CommonJS标准.它输出一个.js允许您require在网站代码中使用的单个.
这有两个缺点,恕我直言:首先是浏览器编译的两个文件可以覆盖它们的require功能,如果它们包含在相同的网站代码中,那么你必须要小心.另一个当然是每次都要运行browserify来更改代码.当然,模块系统代码始终是编译文件的一部分.
所谓的"全球名称空间污染"被大大超过了一个问题.我不知道node.js,但在一个典型的DOM中,默认情况下有数百个全局变量.名称重复很少是明智地选择名称的问题.添加一些使用脚本不会产生丝毫差异.使用如下模式:
var mySpecialIdentifier = mySpecialIdentifier || {};
Run Code Online (Sandbox Code Playgroud)
意味着添加一个可以作为所有代码的根的变量.然后,您可以添加模块到您的内容,例如
mySpecialIdentifier.dom = {
/* add dom methods */
}
(function(global, undefined) {
if (!global.mySpecialIdentifier) global.mySpecialIdentifier = {};
/* add methods that require feature testing */
}(this));
Run Code Online (Sandbox Code Playgroud)
等等.
您还可以使用"扩展"功能来测试和添加基础对象,这样您就不会复制该代码,并且可以轻松地从不同文件向基础库对象添加方法.您的库文档应该告诉您是否在它成为问题之前复制名称或功能(并且测试也应该告诉您).
您的整个库可以使用单个全局变量,并且可以根据需要轻松扩展或修剪.最后,您不依赖任何第三方代码来解决相当微不足道的问题.
我强烈建议您尝试构建工具.
构建工具将允许您在开发时使用不同的文件(即使在不同的文件夹中),并在最后将它们连接起来以进行调试,测试或生产.更好的是,您不需要向项目添加库,构建工具驻留在不同的文件中,并且不包含在您的发行版中.
我使用GruntJS,基本上就是这样的.假设您在js目录中都有您的util.js和index.js(需要定义辅助对象).您可以单独开发它们,然后将它们连接到将由html加载的dist目录中的app.js文件.在Grunt中,您可以指定以下内容:
concat: {
app: {
src: ['js/util.js', 'js/index.js'],
dest: 'dist/app.js'
}
}
Run Code Online (Sandbox Code Playgroud)
这将自动创建文件的串联.此外,您可以缩小它们,拖拽它们,并进行任何您想要的过程.您也可以将它们放在完全不同的目录中,最后仍然会以正确的顺序将一个文件与您的代码打包在一起.您甚至可以在每次保存文件时触发该过程以节省时间.
最后,从HTML中,您只需要引用一个文件:
<script src="dist/app.js"></script>
Run Code Online (Sandbox Code Playgroud)
添加驻留在不同目录中的文件非常简单:
concat: {
app: {
src: ['js/util.js', 'js/index.js', 'js/helpers/date/whatever.js'],
dest: 'dist/app.js'
}
}
Run Code Online (Sandbox Code Playgroud)
而你的html仍然只会引用一个文件.
--------编辑-----------
需要JS(和一些替代品,如Head JS)是一个非常流行的AMD(异步模块定义),它允许简单地指定依赖项.另一方面,构建工具(例如,Grunt)允许管理文件并添加更多功能而不依赖于外部库.在某些情况下,你甚至可以使用两者.
我认为将文件依赖项/目录问题/构建过程与代码分开是可行的方法.使用构建工具,您可以清楚地看到代码,并在一个完全独立的位置指定如何处理文件.它还提供了一个非常可扩展的体系结构,因为它可以通过结构更改或将来的需求(例如包括LESS或CoffeeScript文件)来完成.
最后一点,在生产中使用单个文件也意味着更少的HTTP开销.请记住,尽量减少对服务器的调用次数非常重要.拥有多个文件效率非常低.
最后,这是一篇关于AMD工具构建工具的精彩文章,值得一读.
| 归档时间: |
|
| 查看次数: |
3440 次 |
| 最近记录: |