I just started learning patterns in JavaScript, and getting used to writing JavaScript like this:
(function(window){
var privateVar;
var privateFunc = function(param){
//do something
}
return{
publicFunc: function(){
do something
}
}(window));
But recently I found some scripts that write something like this in the beginning:
(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
}
});
So, what does this piece of code in the beginning mean? What is the difference between that and with this module export technique:
var MODULE = (function () {
var my = {},
privateVariable = 1;
function privateMethod() {
// ...
}
my.moduleProperty = 1;
my.moduleMethod = function () {
// ...
};
return my;
}());
I just started learning patterns in JavaScript, and getting used to writing JavaScript like this:
(function(window){
var privateVar;
var privateFunc = function(param){
//do something
}
return{
publicFunc: function(){
do something
}
}(window));
But recently I found some scripts that write something like this in the beginning:
(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
}
});
So, what does this piece of code in the beginning mean? What is the difference between that and with this module export technique:
var MODULE = (function () {
var my = {},
privateVariable = 1;
function privateMethod() {
// ...
}
my.moduleProperty = 1;
my.moduleMethod = function () {
// ...
};
return my;
}());
Share
Improve this question
edited Jul 14, 2016 at 20:31
Kevin Reid
44.2k13 gold badges95 silver badges122 bronze badges
asked Nov 25, 2014 at 18:16
Ahmad MilzamAhmad Milzam
1293 silver badges8 bronze badges
3
-
It's actually worth noting that the boilerplate code you have could be improved.
window || this
will fail when executed in a Web Worker (a feature in modern browsers). I thinkthis || window
would actually be better. – cloudfeet Commented Nov 25, 2014 at 18:45 - A couple of other resources: davidbcalhoun./2014/what-is-amd-monjs-and-umd and github./umdjs/umd – Sphinxxx Commented Jul 14, 2016 at 20:09
-
@cloudfeet - I see a lot of places (for example the links in my previous ment) that people only use
this
. Will that work in all cases nowadays? – Sphinxxx Commented Jul 14, 2016 at 20:11
1 Answer
Reset to default 10TL;DR: JavaScript modules are loaded in different environments (different module loading systems, or no proper module system at all). The code you have is some boiler-plate code that lets you load a module in these different environments correctly, in a clean way.
In more detail: the actual definition you give is a "factory function": a function that returns the module contents when evaluated. A factory function is a very flexible thing that can be used in a variety of ways.
Browser globals
This is essentially your third example. Here, the factory function is executed immediately, and assigned to a global variable:
var MyModule = (function () {
// this is the factory function
})(); // execute immediately
The result is that other modules can reference this module by using the global variable - but this means you have to be careful to load all the modules in the correct order.
Asynchronous Module Definitions
Asynchronous Module Definition syntax is a pretty simple syntax, which provides a function called define()
(spec here). This lets you describe modules by providing their dependencies and the factory function:
define('module-name', ['dep1', 'dep2'], function (dep1, dep2) {
...
});
So here, module-name
is defined, but the factory function will only be executed when all the dependencies are loaded - this means that you can load the module definitions in any order, and the module loader is responsible for executing them all properly.
CommonJS
In CommonJS environments (such as Node.js, which runs in the mand line or on a server), there is a global(-ish) object called module
. Whatever you assign to module.exports
is considered to be the value of the module.
If you want to use this with a factory function, it's pretty similar to the browser globals scenario, just that you assign it to module.exports
:
module.exports = (function () {
// this is the factory function
})(); // execute immediately
Option (d): All of the above
It's possible to detect which module loaders are available by inspecting the environment (e.g. typeof define
and typeof module
).
The code block at the top detects which module loader is available and uses the factory function with AMD, CommonJS or browser globals, depending which is available.
While you could in theory do this inline in your code, separating it out to the top is nice and neat.