使用 RequireJS 的 Javascript 命名空间,为啥?
Posted
技术标签:
【中文标题】使用 RequireJS 的 Javascript 命名空间,为啥?【英文标题】:Javascript namespacing with RequireJS, why?使用 RequireJS 的 Javascript 命名空间,为什么? 【发布时间】:2012-12-04 23:41:11 【问题描述】:我目前正面临关于 javascript 命名空间的争论,我需要社区意见。
场景: 负责这个项目的架构师不知何故致力于 RequireJS 并且真的很想使用它。
我必须说,该应用程序是一个后台,布局为一个向导,因此您需要在 6 个页面上来回切换,其中包含一些复杂的业务逻辑,最后填写一些我在这里可以描述为流程请求的内容.
好的,没有单页应用程序对这些问题没有任何兴趣。普通的后台 Web 应用程序,多页面,具有非常复杂的 UI,其中每个页面都向服务器请求,并且所有资源(css、javascript 等)都必须在页面加载时加载。
主要问题:了解我们正在谈论的应用类型,为什么首先需要 RequireJS?
第二个问题: 为什么要说服 javacript 中命名空间的最佳方法是使用 RequireJS?我错过了什么吗?
我的看法: 对我来说,这根本没有意义。 这里使用RequireJS很麻烦,因为没有按需加载资源,它们都是在页面加载时加载的(只是因为我们在页面加载时都需要它们)。 我们至少需要支持 IE8、Chrome、Firefox 和 Opera,而且我们已经在所有这些浏览器上加载资源时遇到了很多麻烦。已经有很多技巧可以确保通过 Require 加载所有内容。
对于命名空间,情况更糟。当然可以,但对我来说似乎很麻烦,而且在这件事上实际上非常有限。
所以我错过了什么吗? 我需要第三种(或第 100 种)意见。
您对此有何看法? 你用什么? 为什么?提前致谢
【问题讨论】:
你在 C# 中使用 using 语句吗?这是一回事。 C#“使用”语句与用于 JavaScript 的 AMD 工具完全不同。 "Using" 将命名空间中包含的类型导入直接封闭的编译单元或命名空间主体。 "require" 将指定的模块导入到当前脚本/模块中。听起来和我很相似,但这只是我的看法 AMD 代表异步模块定义,它比 C# 中的所有“使用”的快捷方式和对象命名空间要多得多。 【参考方案1】:AMD 加载器(RequireJS 就是其中之一)解决了不同的问题:
适当的模块化,关注点分离 无全球污染 没有名称冲突 按需加载或部署前优化 根据加载程序,用于解决高级问题(例如本地化资源或加载时编译)的插件我是此类加载器的忠实粉丝,发现它们对所有应用都很有用,但非常小的单页应用程序除外。
【讨论】:
从该列表中,我实际上只将最后两个链接到 AMD 加载程序。 自从我一直为每个页面设置单独的文件以来,关注点被很好地分隔,但没有命名空间。由于客户端站点上的应用程序被声明为较重,我开始将我的代码封装在域函数中,以避免污染全局环境并防止名称冲突。根据我的经验,我知道 RequireJS 不能“正常工作”。所有浏览器(尤其是旧浏览器)的兼容性和稳定性都不是直截了当的,那么为什么要尝试用火箭筒杀死苍蝇呢? @AlexCode 全局变量的缺失完全是 AMD 概念的一部分:requirejs.org/docs/whyamd.html【参考方案2】:无论它是否是“单页应用程序”,RequireJS 在开发客户端 JavaScript 时有助于解决两件在没有大量开发人员纪律的情况下不容易做到的事情:
生产与开发环境
现在将 JavaScript 应用程序拆分为逻辑上类似于应用程序不同部分的文件已成为常识。更容易调试和维护。然而,在生产中,传送许多未压缩的文件对性能不利。因此,您将所有文件连接成一个文件,将其缩小(例如使用 Google 闭包编译器),然后将其作为单个 gzip 压缩文件发送。使用命令行工具有很多不同的方法(例如使用GruntJS),但如果没有像RequireJS这样的脚本加载器,你必须为两个不同的用例设置你的页面(引用你所有的开发文件作为脚本标签或单个 production.js) 自己。 RequireJS 有一个 NodeJS 构建工具,可以为您完成所有这些工作。
模块化
现在将您的代码保存在单独的文件中就很好了。但是由于 JavaScript 的性质和一切都是全球性的,这意味着您仍然可能会遇到奇怪的事情,例如名称冲突。这就是命名空间派上用场的地方。但更好的选择是将所有内容包装到它自己的函数中(这会引入它自己的作用域)。这就是为什么大多数 JavaScript 代码都采用自执行匿名函数的原因。如果这个函数现在返回一个 API,它想公开你有 web 模块。您可以将模块 API 与应用程序分开测试,然后在其他地方重复使用。
还阅读了 RequireJS 文档的 Why Web Modules 部分。
【讨论】:
由于回复,我发布了我自己的问题的答案,解释了我实施命名空间的方式以及原因。实际上,您对依赖于环境的配置有一个真正的强项。谢谢!【参考方案3】:在我个人看来,使用 javascript 模块系统几乎从来都不是一个坏主意。 Requirejs 也不是唯一可能的 javascript 模块加载器(但可能是最流行的一个)。一些替代品是 LABjs 或 HeadJS。
这些加载器通常很容易使用(一开始并没有太大的麻烦),但当项目变得越来越大时可以提供很多帮助。它们避免了全局空间中的命名冲突,还可以通过最小化/优化模块来支持您的部署步骤。最重要的事实是它们允许您编写更模块化的 JavaScript 代码。
您有一些实用功能吗?只需创建一个实用模块。 您在所有页面上都有一些您需要的功能?将它们放在一个公共模块中。 有些页面需要很多特定的javascript代码?为这些页面创建一个额外的模块,这样您就不必在其他页面上加载此代码。【讨论】:
我对您的回答发表了评论。基本上我完全同意你的看法,我只是不喜欢为了实现实际上非常简单和透明的东西而付出的开销和失控。【参考方案4】:我目前防止污染全球环境和名称冲突的解决方案是使用$.extend
。
文件系统树如下所示:
RootFolder
+-> js
global.js
...
+-> views
index.js
page1.js
page2.js
...
index.html
page1.html
page2.html
所以它通常是一个 global.js 文件,其中包含所有应用程序共享代码和另一个特定的每个页面。
对于命名空间我喜欢 $.extend 所以在每个 js 文件上我都有类似的东西:
var app = app || ;
/* only one document ready block per view if needed */
$(document).ready(function()
/* initialization code */
);
/* extend the app namespace with the Page1 code */
$.extend(app,
page1:
SayHi: function SayHi(name)
alert('Hi ' + name);
);
所以你可以通过调用来访问你的代码:
app.page1.SayHi("Alex");
使用这种技术,您:
完全控制您的代码。没有您无法完全控制的神奇资源加载和花哨的东西。 无全球环境污染 没有命名冲突 命名空间树可以任意深,您是自己复杂性的所有者。 您可以拥有多个实际上贡献于同一命名空间级别的 js 文件。这在帮助工具上特别有用。 根据您在页面上包含的 javascript 文件,您可以拥有更大或更小的应用命名空间。结论:
Web 环境真的很简单,我们不应该把它复杂化。
我不是在使用 RequireJS,不要误会我的意思。它做了它的本意(本质上是纯粹的资源延迟加载)。其他一切都是包装附带的东西,但也可以以更清洁和透明的方式实现。
因此,如果我不需要主要功能,那么使用它就没有意义。
干杯!
【讨论】:
在模块中定义 javascript 是推荐的最佳实践。我不相信任何 1 框架都能解决所有问题,但 react 是一个很好的解决方案,它为不支持模块加载的浏览器提供向后兼容性。您竭尽全力避免使用您没有花时间理解的东西,并最终得到了一个不太理想的模式。如果您坚持不使用 require,那么您至少可以了解立即调用的函数表达式,以及它们如何帮助您在 javascript 中安全地定义命名空间。 您正在评论一篇将近 3 年的旧帖子。无论如何,我承认这不是一个好方法,但它更像是一个沮丧的发布 :) 我从来没有实现过任何这些,实际上,几个月后,我们无论如何都将所有东西都转移到了 AngularJS,不再需要 RequireJS。无论如何,所有的决定都不是因为不了解这些工具,而是恰恰相反。以上是关于使用 RequireJS 的 Javascript 命名空间,为啥?的主要内容,如果未能解决你的问题,请参考以下文章
在TypeScript中放置RequireJS定义以从javascript调用
html 使用requireJS的JavaScript类结构。以下代码显示如何在一个JavaScript文件中创建一个类定义,然后是i