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.
Related
I am looking at some code, and I see that it is written as shown below. It doesn't make sense to me. Is it wrong? Why is it written like that? Also, shouldn't the use strict; go at the very top, outside of the code?
(function() {
'use strict';
angular.module('itemList', [])
.component('itemList', {
templateUrl: 'item-list/item-list.component.html',
controller: ['Item', ItemController]
});
function ItemController(Item) {
//code
}
}());
The reason it is wrapped in an IIFE is to keep all declarations like "use strict", functions and variables local to the scope contained within and not set in global namespace
If "use strict" was set global it can affect other unrelated code that my not comply and thus would cause unexpected errors to be thrown
Is it wrong to define controller in...
No. It is a best practice
It is an "immediately-invoked function expression". The main advantage is to make sure you don't pollute the global namespace when declaring local variable.
var someLeakingVar;
function foo(){
//do something with someLeakingVar.
}
The problem with the construct above is that any script coming after will be able to reach/modify someLeakingVar.
If you wrap it within the IIFE. You are sure, only the code within the expression is able to reac/modify it
(function(){
var nonLeakingVar = 'foo';
//...
})()
//here nonLeakingVar is undefined
In the same way as the 'use strict' statement can be function scoped, you make sure only the code within the IIFE will run in strict mode.
You can find more details:
strict mode
IIFE
I was browsing through the source code here: http://js-dos.com/games/doom2.exe.html and noticed a few things:
if (typeof Module === 'undefined')
{
Module = eval('(function() {try { return Module || {} } catch(e) { return {} }})()');
}
The Module function is defined with an inline script tag
It is later declared again with var in another inline tag, this time it checks if the Module exists.
My question: What is the point of declaring Module with a self invoking function if it'll only try to return the Module again? Hasn't it already been proven that it doesn't exist? Why not just explicitly declare Module as {}?
typeof Module might be undefined if Module is a local variable that happens to contain undefined. This code is meant to support a few cases, Module might be local or global, and defined or undefined. We want to avoid polluting the global scope, so we don't just do Module = ... if it's undefined.
First, the usual case is emscripten-generated code in the global scope. In this case, Module may or may not be defined, and may be local but still undefined, so we need to handle both.
Second, emscripten code may be just a module, like a game that uses ammo.js. In that case, the usage is
function Ammo(Module) {
// emscripten-generated code, uses the Module
return something;
}
so Module in this case is a function local, given as a param already defined for us.
We can't just declare var Module because that means Module is a local variable. So we need eval. For eval, we need a function that returns a value, because we need a try-catch. The try-catch uses Module, and will throw if Module is not a local (regardless of whether it contains undefined or not), which is exactly what we want.
It's possible this code could be simplified, though!
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.
I've got some function that allows to merge namespace, very similar to import when the module contains lot's of function (I expose an API with dozens of combinators)
It generates lots of var f = target.f; for every item from the export
function getNamespace(name, exports){
var output='';
for(var item in exports){
output += 'var ' + item + ' = '+name+ '.'+item + ';';
}
return output;
}
and usage:
var paco = require('./paco.js');
eval(paco.getNamespace('paco', paco));
// instead of paco.between(paco.start(),paco.content(),paco.end())
between(start(), content(), end())
Question:
I there a way to 'hide' the eval into the some function ? I don't want neither to mutate global namespace nor to call vm.runInThisContext, just need to add some local variables into the calling context after call function similar to require.
I mean I need something like
import('./paco');
// this should work like this
// var paco = require('./paco.js');
// var between = paco.between;
but without mutation of global and without eval in the calling scope.
tl;dr: No.
In order to understand why this is impossible, it's important to understand what Node is doing behind the scenes.
Let's say we define a function in test.js:
function foo() {
var msg = 'Hello world';
console.log(msg);
}
In traditional browser JavaScript, simply putting that function declaration in a file and pulling the file in with a <script> tag would cause foo to be declared in the global scope.
Node does things differently when you require() a file.
First, it determines exactly which file should be loaded based on a somewhat complex set of rules.
Assuming that the file is JS text (not a compiled C++ addon), Node's module loader calls fs.readFileSync to get the contents of the file.
The source text is wrapped in an anonymous function. test.js will end up actually looking like this:
(function (exports, require, module, __filename, __dirname) {
function foo() {
var msg = 'Hello world';
console.log(msg);
}
});
This should look familiar to anyone who has ever wrapped their own code in an anonymous function expression to keep variables from leaking into global scope in a browser. It should also start making sense how "magic" variables in Node work.
The module loader evals1 the source text from step 3 and then invokes the resulting anonymous function, passing in a fresh exports object. (See Module#_compile.)
1 - Really vm.runInThisContext, which is like eval except it does not have access to the caller's scope
After the anonymous wrapper function returns, the value of module.exports is cached internally and then returned by require. (Subsequent calls to require() return the cached value.)
As we can see, Node implements "modules" by simply wrapping a file's source code in an anonymous function. Thus, it is impossible to "import" functions into a module because JavaScript does not provide direct access to the execution context of a function – that is, the collection of a function's local variables.
In other words, there is no way for us to loop over the local variables of a function, nor is there a way for us to create local variables with arbitrary names like we can with properties of an object.
For example, with objects we can do things like:
var obj = { key: 'value' };
for (var k in obj) ...
obj[propertyNameDeterminedAtRuntime] = someValue;
But there is no object representing the local variables of a function, which would be necessary for us to copy the properties of an object (like the exports of a module) into the local scope of a function.
What you've done is generate code inside the current scope using eval. The generated code declares local variables using the var keyword, which is then injected into the scope where eval was called from.
There is no way to move the eval call out of your module because doing so would cause the injected code to be inserted into a different scope. Remember that JavaScript has static scope, so you're only able to access the scopes lexically containing your function.
The other workaround is to use with, but you should avoid with.
with (require('./paco.js')) {
between(start(), content(), end())
}
with should not be used for two reasons:
It absolutely kills performance because V8 cannot perform name lookup optimizations.
It is deprecated, and is forbidden in strict mode.
To be honest, I'd recommend that rather than doing something tricky with eval, do your future maintainers a favor and just follow the standard practice of assigning a module's exports to a local variable.
If you're typing it that often, make it a single-character name (or use a better editor).
According to this answer Global variables for node.js standard modules? there is global object the same as in browser there is window. So you can add key to that object
function getNamespace(exports) {
for(var item in exports){
global[item] = exports[item];
}
}
and use it as:
paco.getNamespace(paco);
no need for eval at all.
No. It's not possible to modify the local scope from an external module. Reason being, when eval is called in the external module, its context will be the external module, not the scope requiring the module.
In addition, vm.runInThisContext does not have access to the local scope, so that wont help you either.
A while ago, I offered-up a JavaScript design pattern (the Module Pattern - see below) that I got from a John Resig example as part of a solution to someone’s question and I received the following comment:
“…that pattern is a bit over
engineered and not that good. Still
leaking into global-scope. and your
not opening yourself to async loaders.
But it is better then just ad-hoc
coding !”
So…
If “leaking” into global scope means “your object gets appended to the browsers window (object)”…then everything already gets appended (globally):
This “leaks” into global scope:
window.jQuery
…just call: window.jQuery and it resolves as a function();
This “leaks” into global scope:
function HelloWorld() { alert(‘Howdy’); }
…just call: window.HelloWorld() and you will get ‘Howdy’.
This “leaks” into global scope:
var myVariable = 10;
…just call: window.myVariable and you will get 10
If the commenter is correct, then all the above “leak” into global-scope. So, personally, I don’t see a way NOT to “leak” into global-scope as even your form controls exists there (as well).
As such, here are my questions…
What is meant by “leaking” into
global-scope?
Why is that bad?
How do you avoid it?
When wanting to create persistent
custom-objects, why is the Module
Pattern (below) bad?
Design patterns let you encapsulate
complex logic, is encapsulation
suddenly bad simply because we’re
writing in JavaScript?
Or...is this commenter simply wrong?
Here is the Module Pattern I Mentioned Above:
<script type="text/javascript">
var myNamespace = (function($) {
var publicInstances = {};
// ***********************
// myObject
publicInstances.myObject = myObject;
function myObject() {
/// <summary>A pointer to this</summary>
var self = this;
this.someProperty = new String();
this.initialize = function() {
/// your code here
}
this.someMethod = function() {
/// your code here
}
self.initialize();
}
return publicInstances;
})(jQuery);
jQuery(document).ready(function() {
// Use would look like
var myInstance = new myNamespace.myObject();
});
</script>
UPDATED:
I’m satisfied with the answers below and want to thank everyone for taking the time to comment.
TO RECAP THE ANSWERS BELOW:
"Leaking" into global-scope occurs when something used in local-scope is unintentionally made available to the global-scope (e.g. the window object). This is bad because it opens the page to potential naming collisions which could result in variables resolving to unexpected values or types.
Intentionally making a variable global is not considered a "leak". However, properly namespacing the object is required to reduce potential for said naming collisions.
You cannot avoid globally-scoped variables, but you can reduce the above risks by using asynchronous-loaders and defining-modules made available in plug-ins like RequireJS or Curl.
"Leaking" into global scope is when something used in a local scope is unintentionally made available to the global scope. That means assigning to a variable not already defined in the current scope:
function myFunction() {
a=1;
}
myFunction();
alert(a);
//-> 1
It's bad because there could be naming collisions resulting in variables with different values/types than expected. It can also lead to a bug in older Internet Explorers when you forget to use the var keyword for a variable used in a for statement.
I wouldn't class intentionally making a variable global as "leaking", because it's more like you're "pouring" it into the global scope. However, this is still often considered bad practice by some (although I think that's a little melodramatic) because there are still potential naming collisions with current properties of the window object, or variables set by other scripts and libraries.
[[Short story]]
Don't make global variables ever and use an async module loader like requirejs or curl
[[Long story]]
That comment was poorly structured.
There is nothing wrong with the module system. I was complaining about using global variables at all. (I still think the full generic module pattern is bloated).
Whether you should avoid all global variables is a different question and I think a matter of style. You can either use an async loader to pass modules around or using window to pass modules around.
What is meant by “leaking” into global-scope?
What I meant was your creating global variables. Minimising the use of global variables is a pattern. In functional style programming it's possible to have zero global variables but this is a different pattern from using global modules.
Why is that bad?
Having any state globally can cause that state to be corrupted.
How do you avoid it?
You can't. You can minimize the amount of global variables though. To avoid having global state completely you can use asynchronous loaders. These define a few global variables for you that you can then use.
When wanting to create persistent custom-objects, why is the Module Pattern (below) bad?
There is nothing wrong with the module pattern. The problem is storing your module globally. The issue is having global namespaces.
Design patterns let you encapsulate complex logic, is encapsulation suddenly bad simply because we’re writing in JavaScript?
Now that I've cleared up the intent of the comment this question isn't really relevant
Or...is this commenter simply wrong?
The comment was poorly phrased at best. I objected to global namespaces rather than modules, but did not state this properly.
The alternative is using asynchronous loaders and defining modules. These can be narrowed down to two global variables. define and require.
require = function(moduleName, callback)
This will get a module and then return it to you.
define = function(obj)
this defines a module.
The concept here is that you multi file code as follows:
// main.js
require([
"foo.js",
"bar.js",
...,
], function(foo, bar, ...) {
// do stuff
});
//foo.js
(function() {
var namespace = modulePatternCode;
...
define(namespace):
})();
//bar.js
(function() {
var namespace = modulePatternCode;
...
define(namespace):
})();
Your module only "leaks" it's namespace holder so it's pretty acceptable.
Loader example using RequireJS:
Define a utilities module in utils.js:
define(function () {
return {
each: function (iterable, callback) {
// ...
},
map: function (iterable, mapper) {
// ...
}
};
});
Use the above module in another module, say math.js:
define([ "utils" ], function (utils) {
return {
sum: function (numbers) {
var sum = 0;
utils.each(numbers, function (n) {
sum += n;
});
return sum;
},
average: function (numbers) {
return this.sum(numbers) / numbers.length;
}
};
});
And you can use math.js in another file, say main.js:
console.log("About to add 1-3");
require([ "math" ], function (math) {
console.log(math.sum([ 1, 2, 3 ]));
});
You can still have namespaces, and still keep them warm and cozy inside modules:
namespace.js:
define([ "foo", "bar", "moo" ] function (foo, bar, moo) {
return {
foo: foo,
bar: bar,
moo: moo
};
});
Then the rest of the modules can use this namespace during definition:
define([ "namespace" ], function (namespace) {
namespace.foo(42);
});
Or at runtime, in some other module:
define(function () {
return {
initialize: function () {
require([ "namespace" ], function (namespace) {
namespace.foo(42);
});
}
};
});
In the usages above, nothing but define and require are global. Of course, these are just illustrative examples, as there are many different flavors of defining/using modules in RequireJS.