问题
I am using the following closure pattern to modularise my code:
(function(root) {
// MODULE CODE HERE
if (typeof module !== 'undefined' && module.exports) { // CommonJS
/* var dependencies = require(...) */
module.exports = myModule;
} else if (typeof define !== 'undefined' && define.amd) { // AMD
/* var dependencies...; */
define([/* dependencies */], function(/* dependencies */) {
/* Assign closure level vars to respective arguments */
return myModule;
});
} else {
// Dependencies??
root.myModule = myModule;
}
})(this);
i.e., We use feature detection to support CommonJS modules (e.g., node.js), AMD or basic global namespace instantiation.
This works fine in node.js; I haven't tested the AMD pattern yet, as I'm still reading up on it (See Edit 2: AMD exhibits the exact same effect); but it fails in the browser if the module has any dependencies. That is, say, if myModule
references something that is defined in a different module: For example, say if I had super.js
and child.js
with respective module definitions, as above, where super.js
creates a function called root.super
(root === window
in the browser), if child.js
tries to do super()
, I will get something like super is not a function
.
What's going on here?
To try to fix it, I changed the order in which super.js
and child.js
are loaded in <script>
elements: No luck. Then I tried forcing child.js
to load when the document is ready, using jQuery:
$(document).ready(function() {
$.getScript('child.js', function() {
// Do stuff with child, which calls super
});
});
...again, same problem. However, in both cases, if I enter the console, super
is available and defined as I'm expecting.
Why is super
in child.js
presumably from a different (i.e., not the global) scope?
I should add, if I remove the dependency injection bit in the CommonJS export, it fails in node.js with the same error (if there are any dependants).
EDIT @Amberlamps' answer solved the problem, but it didn't answer the question as to why this occurs. My module pattern is now:
(function(root) {
// MODULE CODE HERE
if (typeof module !== 'undefined' && module.exports) { // CommonJS
/* var dependencies = require(...) */
module.exports = myModule;
} else if (typeof define !== 'undefined' && define.amd) { // AMD
/* var dependencies...; */
define([/* dependencies */], function(/* dependencies */) {
/* Assign closure level vars to respective arguments */
return myModule;
});
} else {
if (root.hasOwnProperty(/* dependencies */)) {
/* var dependencies = root... */
root.myModule = myModule;
}
}
})(this);
This keeps dependants with a common name, across environments. However, the question remains: Why is the global object not available within the closure's scope?
EDIT 2 I've been experimenting with RequireJS and AMD and have corrected my code, above, so that the AMDs work. Exactly the same thing happens in this case, too: You have to explicitly assign the global object to a variable within the closure for it to be available within said closure...
回答1:
This pattern works just fine. If you actually tested it with a function called super
and calling it via super()
, you might ran into an error, because super
is a reserved word. Following code works fine:
(function(root) {
root.super = function() {
console.log("hello");
};
}) (window);
(function(root) {
root.super();
}) (window);
You can call your function using window.super()
. super()
however will result in an error.
来源:https://stackoverflow.com/questions/14381501/javascript-modules-closures-and-scope