With my limited understanding of RequireJS and Node.js (plus JavaScript in general), I usually take a look at the source of some well-known JavaScript libraries. Every time I see something like this:
( // Wrapping
function (root, factory) {
if (typeof exports === 'object') { // Node.js
var underscore = require('underscore');
var backbone = require('backbone');
module.exports = factory(underscore, backbone);
} else if (typeof define === 'function' && define.amd) { // Require.JS
define(['underscore', 'backbone'], factory);
}
}(this, function (_, Backbone) { // Factory function, the implementation
"option strict";
function Foo() {}
return Foo; // Export the constructor
})
); // Wrapping
What I can understand (hopefully):
- The anonymous function that wraps the code is automatically executed when the script is uncluded in a
<script>
tag - This code works with both RequireJS and Node.js (
if
checks in the very beginning); the result offactory
function is either assigned tomodule.exports
(Node.js) or used as argument ofdefine
function (RequireJS).
Q1: how this code works without RequireJS and Node.js? if
and else if
checks would fail, factory
function is never executed and the scripts returns nothig.
Q2: what's the purpose of passing this
as root
argument? It's never used
With my limited understanding of RequireJS and Node.js (plus JavaScript in general), I usually take a look at the source of some well-known JavaScript libraries. Every time I see something like this:
( // Wrapping
function (root, factory) {
if (typeof exports === 'object') { // Node.js
var underscore = require('underscore');
var backbone = require('backbone');
module.exports = factory(underscore, backbone);
} else if (typeof define === 'function' && define.amd) { // Require.JS
define(['underscore', 'backbone'], factory);
}
}(this, function (_, Backbone) { // Factory function, the implementation
"option strict";
function Foo() {}
return Foo; // Export the constructor
})
); // Wrapping
What I can understand (hopefully):
- The anonymous function that wraps the code is automatically executed when the script is uncluded in a
<script>
tag - This code works with both RequireJS and Node.js (
if
checks in the very beginning); the result offactory
function is either assigned tomodule.exports
(Node.js) or used as argument ofdefine
function (RequireJS).
Q1: how this code works without RequireJS and Node.js? if
and else if
checks would fail, factory
function is never executed and the scripts returns nothig.
Q2: what's the purpose of passing this
as root
argument? It's never used
- 1 Are you sure that it does work without RequireJS or Node.js? My limited understanding of JavaScript (and this possibly wrong) JSFiddle makes me think you can't access Foo() – Jason Sperske Commented Feb 8, 2013 at 21:17
- @nekman Ahh I see it assumes at least Backbone is available. That's smart – Jason Sperske Commented Feb 8, 2013 at 21:18
- @JasonSperske not sure at 100%, but look at nekman answer... – gremo Commented Feb 8, 2013 at 21:22
2 Answers
Reset to default 5Actually I think the code snipped in your question will not work with browser globals. The pattern used in this snipped is called UMD - Universal Module Definition. In fact there are many variations of this pattern, you can browse more examples on https://github./umdjs/umd
As for the questions:
Q1 This snippet will not work in browsers without RequireJS or any other AMD loader, for obvious reasons - there only two checks - for the NodeJS and define function, so without using AMD library the factory function won't be called.
To make the factory function called just add another condition for browser globals
if (typeof exports === 'object') { // Node.js
var underscore = require('underscore');
var backbone = require('backbone');
module.exports = factory(underscore, backbone);
} else if (typeof define === 'function' && define.amd) { // Require.JS
define(['underscore', 'backbone'], factory);
} else {
// Browser globals
factory(root._, root.Backbone);
}
Note that we used root object passed to the wrapper function and as nekman pointed out it will be set to window
in browser environment, so we just pass global objects defined on that window to the factory, these objects usually defined by other script
tags on the page. Hope this answers your second question.
Q1: If both the if
and the else if
fails, the only thing to assume is that underscore
and Backbone
is loaded from a <script>
tag. For a while ago, I added a mit to the Backbone.localStorage plugin that did the same assumption.
Q2: The this
will point to the "global object" (window
in a browser environment and global
in a Node.js environment). In your case, it isn't used and do not need to be passed in. The factory
alone would be enough.