我刚刚开始在JavaScript中学习模式,并习惯于编写这样的JavaScript:
(function(window){
var privateVar;
var privateFunc = function(param){
//do something
}
return{
publicFunc: function(){
do something
}
}(window));
但最近我发现一些脚本在开头就写了这样的东西:
(function (root, factory) {
if ( typeof define === 'function' && define.amd ) {
define('something', factory(root));
} else if ( typeof exports === 'object' ) {
module.exports = factory(root);
} else {
root.something = factory(root);
}
})(window || this, function (root) {
var privateVar;
var privateFunc = function(param){
//do something
}
return{
publicFunc: function(){
do something
}
});
那么,这段代码在开头意味着什么呢?它与此模块导出技术之间有什么区别:
var MODULE = (function () {
var my = {},
privateVariable = 1;
function privateMethod() {
// ...
}
my.moduleProperty = 1;
my.moduleMethod = function () {
// ...
};
return my;
}());
答案 0 :(得分:8)
TL; DR: JavaScript模块加载在不同的环境中(不同的模块加载系统,或根本没有适当的模块系统)。您拥有的代码是一些样板代码,可以让您以干净的方式正确地在这些不同的环境中加载模块。
更详细地说:您给出的实际定义是"工厂函数":在评估时返回模块内容的函数。工厂功能是一种非常灵活的功能,可以通过多种方式使用。
这基本上是你的第三个例子。这里,工厂函数立即执行,并分配给全局变量:
var MyModule = (function () {
// this is the factory function
})(); // execute immediately
结果是其他模块可以使用全局变量引用此模块 - 但这意味着您必须小心以正确的顺序加载所有模块。
异步模块定义语法是一种非常简单的语法,它提供了一个名为define()
(spec here)的函数。这使您可以通过提供依赖项和工厂函数来描述模块:
define('module-name', ['dep1', 'dep2'], function (dep1, dep2) {
...
});
所以这里定义了module-name
,但只有在加载所有依赖项时才会执行工厂函数 - 这意味着您可以按任何顺序加载模块定义,并且模块加载器负责执行他们都很合适。
在CommonJS环境中(例如在命令行或服务器上运行的Node.js),有一个名为module
的全局(-ish)对象。您分配给module.exports
的任何内容都被视为模块的值。
如果你想将它与工厂函数一起使用,它与浏览器全局方案非常相似,只需将它分配给module.exports
:
module.exports = (function () {
// this is the factory function
})(); // execute immediately
通过检查环境(例如typeof define
和typeof module
),可以检测哪些模块加载器可用。
顶部的代码块检测哪个模块加载器可用,并使用AMD,CommonJS或浏览器全局变量的工厂函数,具体取决于哪个。
虽然理论上你可以在你的代码中内联这些内容,但将它分离到顶部是很好的和整洁的。