It seems to be that if you are using RequireJS and you use define and require, then there is not point of using IIFE as well, since each module is already wrapped in a define/require. Is that the case?
In other words, does this code
define(['app'], function(app)
{
app.run();
});
has any difference/advantage to
(function() {
define(['app'], function(app)
{
app.run();
});
})();
Generally, you don't need to use an IIFE with RequireJS but sometimes you should.
If you use the usual define([... deps ...], function (...) {...}) format then you are only reading define from the global space and everything else you do is encapsulated inside the function you pass to define. With or without an IIFE, you can leak what you want to leak and keep private what you want to keep private.
The IIFE will typically be desirable if you are writing code that you want to be able to run with and without RequireJS. For instance, this:
(function () {
'use strict';
function factory () {
// Build our module...
return something;
}
if (typeof define === 'function' && define.amd)
define([], factory); // AMD environment: call define.
else
window.Foo = factory(); // Otherwise, leak into the global space.
})();
Popular libraries (e.g. jQuery) often have code like this that allows using them with RequireJS (or another AMD loader) and with script elements. This is extremely common. Using the IIFE allows to keep the factory function out of the global space.
The define() function is in Global scope anyway, so calling it inside an IIFE doesn't make a difference at all and it's kind of redundant.
It would be different if you put code outside of the define callback but you shouldn't do that because each file should represent an encapsulated module.
The only time I can think of using an IIFE with RequireJS might be when I'm configuring my application by calling require.config() before initialization; but even then if I'm just calling require.config() and don't have any code on the outside, I still wouldn't use an IIFE.
In this example here there wasn't a need to use an IIFE: https://github.com/vasilionjea/bower-requirejs-starter/blob/master/local/js/main.js
I hope that answers your question.
Related
I am using Node.js. I defined a custom method to the String obj like this:
if (!String.prototype.myMethod) {
String.prototype.myMethod= function () {
//do something
return this;
};
}
I found that myMethod maybe used in many different files, so that I have to require the file where this piece of code in. Is there any way that does the many 'requires' ?
Don't do that.
Node is intentionally designed in a module pattern, where each module gets it's own scope to run in and without polluting the global variables. This very intentional and very important.
https://nodejs.org/api/modules.html#modules_the_module_wrapper
I have noticed a lot of libraries use this style below to define their library. I also notice that the first self invoking function has something to do with Require.js or AMD systems, they always have factory as an argument, I will look more into Require.js, always been into Browserify.
Why is the main code passed into the end of the first self invoking function inside parentheses, is this is a closure, or just considered an anonymous function, I will dig deeper into both. What are the benefits to this? It looks like inside the closure the author passes a string, this, and a callback.
Will this give my library a clean safe way to globalize the main object in this example below Please?
(function( globalName, root, factory ) {
if ( typeof define === 'function' && define.amd ) {
define( [], factory );
}
else if ( typeof exports === 'object' ) {
module.exports = factory();
}
else{
root[globalName] = factory();
}
}('Please', this, function(){
I am trying to dig really deep into JavaScript and create my own small MVC architecture, I don't want to hear I am silly or its been done before, I want to challenge myself and learn.
If there are any great resources for creating a JavaScript library or even better an MVC library I would love to know.
This code pattern is called Universal Module Definition (UMD). It allows you to make your JavaScript library usable in different environments. It provides three ways of defining modules:
Asynchronous Module Definition (AMD), implemented by RequireJS and Dojo Toolkit.
define( [], factory );
CommonJS — NodeJS modules.
module.exports = factory();
Assigning module to the global object, for example window in browsers.
root[globalName] = factory();
The IIFE has three parameters: globalName, root and factory.
globalName is the name of your module. It applies only to the third way of defining a module, i.e. assigning your module object to the global variable. For example, if you set this parameter to "myAwesomeModule" and use the code in browser (without AMD), you can access your module using myAwesomeModule variable.
root is the name of global object. Obviously, it also applies only to the third way of defining a module. Usually this is passed as this parameter, because this is a reference to window in browser. However, this doesn't work in strict mode. If you want your code to work in strict mode, you can replace this with typeof window !== "undefined" ? window : undefined.
Finally, factory is an anonymous function, which should return your module as object.
See also:
What is the (function() { } )() construct in JavaScript?
What Is AMD, CommonJS, and UMD?
This is an example of Universal Module Definition (UMD). It is a technique to make a JS module compatible with the three popular JS module specs:
Asynchronous Module Definition (AMD, used by Require.js)
define('name', [ /* dependencies */ ], factory);
CommonJS (Node.js ecosystem)
module.exports = object;
Global exports (for example, on window in the browser)
global['name'] = object;
UMD wraps a factory function responsible for creating the object to be exported and passes it as an argument to an immediately invoked function expression (IIFE), as in the snippet you pasted. The IIFE is responsible for detecting the module environment, and exporting the object created by the factory in an appropriate way. The pattern is as follows:
(function (name, root, factory) {
// detect the module environment and
// export the result of factory()
})('name', this, function () {
// module code
// return the object to be exported
});
Many transpilers and build tools generate this wrapper automatically.
In a simple UMD setup like the following, where/how are root and factory defined?
(function (root, factory) {
// environment detection here
console.log(root);
console.log(factory);
}(this, function (b) {
// module definition here
}));
I'm arriving late to the UMD party, so please forgive me if this is a silly question... but if I run the above code, I see root returns the window object, and factory returns a function. So is the first argument (in this case, root) always defined as the window object? What about the second? Are they implemented the same cross browsers? I'm searching high and low for a spec or reference to back this up and can't find one... there are lots of blog posts about the wonders of UMD, but I can't find any explanation of how this magically works.
Does anybody have a simple explanation for how or why this works?
This is an IIFE (immediately-invoked function expression), which is nicely explained here.
To put it simply you are creating a function that is only called once and you are passing to it two arguments, this and function(b). These two arguments are named root and factory inside the IIFE body.
The benefit is that the body of IIFE works in isolation, in a "private scope". Variable names outside of it have no effect and you have no conflict problems.
Now, back to your question, you are passing this as an argument. This is the global object. In a browser it is window and in Node it is global. In both cases in the IIFE you are referring to it as root and in your module as b. What ever you call it, another advantage is that your minifier can pick it up and translate it to c or something else without breaking your code. This is in contrast with a normal situation, where window or document or any module names can't be minified.
You are also passing a function, which is named factory. This is your module. Without AMD or CommonJS, you would usually do:
(function (root, factory) {
root.myModuleName = factory(root);
}(this, function (b) {
// module definition here
}));
This will create your module and attach it to the global object, so that you can use it. With only one argument in factory method, you normally need to pass the global object. You can also use more arguments to pass any module dependencies:
(function (root, c, factory) {
root.myModuleName = factory(root, c);
}(this, jQuery, function (b, $) {
// module definition here
// You refer to jQuery as $ without having to call noConflict
}));
Not always. root could be global in Node or in the browser it could be window. It is passed by providing this. factory is the function that is after this with the argument b. That is where the application code ("business logic" or "meat") is.
UMD should work in any JavaScript environment, it just adapts the logic for what ever module loading system is present.
I have been writing modules in nodejs as following :
module.exports = function (logger, db, external,constants) {
return {
//something
}
}
Recently someone in my team suggested that whole script should be wrapped in a function to avoid global confusion of variables i.e. like this :
(function () {
'use strict';
module.exports = function (logger, db, external,constants) {
return {
//something
}
}
}());
I understand that this practice is generally used at client side code. But during server side in nodejs is this required? I think that in nodejs there is really no global scope and only module.exports is the one which is accessible really irrespective of whatever we write in script file (ofcourse don't go wild over here).
No, IIFEs aren't required with Node.js.
They can be useful for any scripts that may be used in multiple environments (UMD).
But, each module/file executed by Node.js is given a "module scope," similar to the scope an IIFE provides, as described under "Globals":
In browsers, the top-level scope is the global scope. That means that in browsers if you're in the global scope var something will define a global variable. In Node this is different. The top-level scope is not the global scope; var something inside a Node module will be local to that module.
Though, there is still a global scope with Node.js. When a module creates a global, it will be accessible in other modules used by the same process.
foo = 'bar'; // lack of `var` defines a global
console.log(global.foo); // 'bar'
You're actually already doing this.
What he's suggesting is to wrap the entire script in a function like this:
function () {
}
That's all. Nothing special. Of course, in regular javascript a function definition just defines a function and the code inside the function doesn't run. So to automatically run the function you wrap it in an expression context and invoke it:
(function () {
})()
However, in node.js you don't need to do this. Instead you can simply call the function when you require the module. So in node.js, this does the exact same thing in terms of creating a private scope:
module.exports = function () {
}
So tell your friend you're already wrapping the entire script in a function.
This is perhaps the first case that I see the harm in naming things and design patterns. In this case your friend is thinking IIFE. But IIFE is nothing special. IIFE doesn't create a private scope. It's functions that create scope. IIFE is just a means for the function to call itself. Which is why I prefer calling it self-calling-function to avoid giving it a sense of magic which may cause some people to perceive it as something special.
I'm writing an AMD internationalization module. It exports a single function that receives a string to translate and returns the translation, in a fashion similar to gettext.
I need to load the appropriate translation file from within said module, but it has to be done synchronously and with respect to a definition in the settings module.
How can I require a module synchronously and then require another module, also synchronously?
Whenever you see code that uses RequireJS and appears to run synchronously, that's just appearance. For instance, you may see:
define(function (require, exports, module) {
var foo = require("foo");
// ...
});
and think that require("foo") is just a synchronous call. In a sense, it is synchronous because it returns a value immediately. However, what you don't see is that the module definition is processed as if it were:
define(["require", "exports", "module", "foo"], function (require, exports, module) {
var foo = require("foo");
// ...
});
The module foo was loaded asynchronously before RequireJS ran the callback passed to define, so require("foo") is not really asynchronous. It just looks this way.
One upshot of how these pseudo-synchronous calls work is that you cannot generally call require(x) where x is a string computed at run time. (Note that you can call require(x) where x is an array computed at run time, and can be followed by an optional callback. This is the "regular" asynchronous require. No problem here.) I said "generally" because there are cases where it can work. For instance, if you have a known and small set of possible values for x, you could define your module like this:
define(["a", "b", "c"], function () {
var x = something(); // Where something() can be only return "a", "b", or "c".
var module_x = require(x);
// ...
});
This would work because I'm listing all possible modules I might want to use in the dependencies of the define call, and because something() can only return the name of a module that is already loaded. In cases where the set is unknown ahead of time or requiring all possible modules would defeat the purpose of modularization, then you can't do this. I'd expect that in the case of an internationalization module, you would not want to load all languages so you could not do this.
RequireJS, by itself, won't work here.
What you could do is have your internationalization module return promises instead of strings. Or there may be a plugin out there that could help but I would not know about it.