我认为您的解释有点误导:在这两种情况下,您都会有一个顶级require
调用,其data-main
属性指定一个文件,以启动需要不同模块的过程。
所以通常你会在你的 HTML 中有这个:
<script data-main="app/config" src="assets/js/libs/require.js"></script>
然后,在这两种情况下,您都会有一个文件app/config
来设置您的配置(尽管您可以直接在 HTML 中执行此操作)并且更重要的是调用require
您的模块:
require.config({
paths: {
jquery: '../assets/js/libs/jquery'
}
});
require(['app']);
现在,当我们开始定义具有依赖关系的模块时,这些样式会有所不同。在 amd 样式中,您将模块名称(路径)作为数组传递,以及一个接受相同数量参数的函数:
应用程序.js
define(['module/first', 'module/second', 'module/third'], function (firstModule, secondModule, thirdModule) {
// use firstModule, secondModule, thirdModule here
});
在简化的 CommonJS 语法中,您只需传入require
然后define
require 内联所需的任何模块:
应用程序.js
define(function(require) {
var firstModule = require('modules/first');
var secondModule = require('modules/second');
var thirdModule = require('modules/third');
// use firstModule, secondModule, thirdModule here
}
回到你最初的问题,CommonJS 风格相对于 amd 风格的优势应该很明显。
一方面,使用常规语法,如果需要许多模块,很容易错误地将模块分配给错误的变量名。考虑这种常见情况:
define(['jquery', 'underscore', 'backbone', 'modules/first', 'modules/second', 'modules/third', 'i18n', 'someOtherModule'], function ($, _, Backbone, first, second, third, I18n, someOtherModule) {
// ...
});
马上,你可以看到当我们向这个列表中添加一个新模块时,我们必须非常小心相应的新函数参数出现在正确的位置,否则我们可以将 jQuery 分配给Backbone
等等。在某些情况下,这可以创建很难追踪的非常微妙的错误。
现在考虑 CommonJS 语法:
define(function(require) {
var $ = require('jquery');
var _ = require('underscore');
var Backbone = require('backbone');
var firstModule = require('modules/first');
var secondModule = require('modules/second');
var thirdModule = require('modules/third');
var I18n = require('i18n');
var someOtherModule = require('someOtherModule');
// ...
}
注意:
- 模块与变量名的配对非常清晰。
- require 语句的顺序并不重要,因为变量名称是单独配对的,而不是作为数组和函数之间的映射。
- 不需要先分配模块。只要在实际使用模块之前,它们就可以分配到任何地方。
这些只是我想到的几个原因,我相信还有其他原因。基本上,如果您只有一个或两个依赖项,那么任何一种语法都可以。但是如果你有一个复杂的模块依赖网络,CommonJS 语法可能更可取。
请注意,在 RequireJS 文档中,他们提到了这个小警告:
并非所有浏览器都会给出可用的 Function.prototype.toString() 结果。截至 2011 年 10 月,PS 3 和更早的 Opera Mobile 浏览器不支持。这些浏览器更有可能需要针对网络/设备限制的模块的优化构建,因此只需使用知道如何将这些文件转换为规范化依赖数组形式的优化器进行构建,例如 RequireJS 优化器。
但这不是主要问题:
由于不支持这种 toString() 扫描的浏览器数量非常少,因此对所有模块使用这种糖化形式是安全的,特别是如果您希望将依赖项名称与将保存其模块值的变量对齐。