我认为你的解释有些误导:在这两种情况下,你都将拥有一个顶层
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风格中,您将模块名称(路径)作为数组传递,并传递一个函数,该函数接受相同数量的参数:
app.js
define(['module/first', 'module/second', 'module/third'], function (firstModule, secondModule, thirdModule) {
});
在简化的CommonJS语法中,你只需要将
require
传递到
define
中,然后内联地引用所需的任何模块:
app.jsdefine(function(require) {
var firstModule = require('modules/first');
var secondModule = require('modules/second');
var thirdModule = require('modules/third');
}
回到您最初的问题,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()扫描的浏览器数量非常少,因此可以安全地将这些带糖形式用于所有模块,特别是如果您喜欢将依赖项名称与将保存其模块值的变量对齐。