I am just about to get the hang of this, but I still have one question
I have 2 modules contained in their own js files. One is based on the module pattern and the other the revealing module pattern. The confusion I have surrounds the assignment of a variable to these functions. The code below should help
Revealing module example. If I run this example I see a var1 variable in the global namespace with a doStuff public function
var var1 = (function() {
function doStuff() {
};
return {
doStuff : doStuff
}
})();
Module pattern example. If I run the example below in the debugger I can see the this.var2 line getting executed, but I do not see a var2 variable in the global namespace
(function() {
function doStuff() {
};
this.var2 = doStuff;
})();
Just wonder whether anyone can help explain what is most likely my misunderstanding.
Thanks
Related
The main benefit of modules (that I've heard) is that they hide private variables.
var Module = (function() {
var privateProperty = 'foo';
return {
publicProperty: '...',
publicMethod: function(args) { ... }
}
})();
But the IIFE isn't necessary to do this. If you just remove it, privateProperty would be hidden anyway. So why use the IIFE? I'm trying to understand the rationale.
EDIT:
I keep reading that privateProperty without IIFE would be part of the global scope. I think this is wrong.
If I do the following:
console.log(privateProperty); // => Reference Error: privateProperty isn't defined
I get a reference error. If I do this:
console.log(Module.privateProperty) // => undefined
I get undefined. If I do this:
var mod = new Module();
console.log(mod.privateProperty); // => undefined
I get undefined. Global scope can't access local scope in JS.
EDIT 2:
test.js
var test = (function() {
var privateProperty = 'foo';
return {
publicProperty: 'bar',
}
})();
test.js
var test1 = function() {
var privateProperty = 'foo';
return {
publicProperty: 'bar',
}
};
index.html
...
<script src="./test.js"></script>
<script src="./test1.js"></script>
<script>
console.log(test.privateProperty); // => undefined
console.log(test1.privateProperty); // => undefined
</script>
When I try the above, I don't have access to privateProperty in either case. Where is the name collision people are talking about? What is IIFE solving?
privateProperty would be hidden anyway
No, without the IIFE, privateProperty would be a property of the global scope.
Unless you're talking about a Module-loader, which (behind the scenes) basically does the same as the IIFE, it wraps the whole file in a function, a bit like:
var factory = Function("require, module, exports, global", yourFileBody );
and then calls the factory with the proper values; that's also the reason you have these mechanics; because they are injected as function arguments.
That's how these "private" properties don't pollute the global Namespace.
Edit:
I tried an example without any module.exports, but I still don't understand what problem point IIFEs are solving. I posted the example in Edit 2
test1 is a factory, not a module. Let's remove the factory and extract the generated Module, and let's make some minor changes so that this private state makes sense. (turn publicProperty into a function "speak" and actually use the private property/value/state there)
//the generted Module boils down to:
var test1 = {
name: "test1",
speak() {
return this.name + " says " + private;
}
};
//and the private state also has to be kept somewhere:
var private = "Hello World";
Now let's check the Module
console.log("test1", test1);
console.log("test1.speak()", test1.speak());
console.log("test1.private", test1.private);
Fine, everything as expected
But wait, what's this?
console.log(
"Look here:",
private,
this.private,
window.private
)
Oh no, someone exposed my private property! Everybody can see it.
What might happen if some other Script also defines a private property?
var private = "Bye Folks";
var test1 = {
name: "test2",
speak() {
return this.name + " says " + private;
}
};
console.log("test2", test2);
console.log("test2.speak():", test2.speak());
Fine, fine. What about ...
console.log("test1.speak():", test1.speak());
Oh No, test1 is broken. It's supposed to say "Hello World" ... I'd wish there was a way to make my private property really private so that other's don't mess around with it.
https://jsfiddle.net/crkguf6b/
#jro, do you now understand? Such factories encapsulate the private state so that it doesn't pollute the global namespace, and that it can't get messed up by some different code; while exposing only a public API.
The IIFE you started your question with, is actually an anonymous factory that gets immediately invoked to create exactly one instance of this Object/Module, and then gets GC. And as shown at the top, Module loader do it the same way. They create these factories behind the scenes (or in a preprocessing step) out of your JS-files, and invoke them when necessary.
Conclusion:
It's not intrinsic to the language, that privateProperty is private. It's "artificial". Without the module loader that wraps your JS-file in a function, without the factory, and without the IIFE, privateProperty ain't private.
Maybe this will change with ES6 Modules. Maybe it will get an intrinsic part of JS, that each file is seen as a separate Module, and therefore a plain var foo; in the file won't end up in the global Namespace, but at the moment it's not.
Your test1 file contains a plain function, not a module pattern and not a no-module pattern. Try this:
<script>
var testA = (function() {
var privateVariable = 'bar A';
return {
publicProperty: 'foo' + privateVariable
}
})();
</script>
<script>
var privateVariable = 'bar B';
var testB = {
publicProperty: 'foo' + privateVariable
};
</script>
<script>
console.log(testA.publicProperty); // => 'foobar A'
console.log(testB.publicProperty); // => 'foobar B'
console.log(privateVariable); // => 'bar B'
</script>
It's not about properties of anything, it's about global scope in scripts.
Without the module, you have to use another variable.
var Test = new test(someX);
and then access the properties as Test.replace.
With the module pattern, you can simply use
Module.publicProperty
immediately after you load it.
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 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.
This is a JS newbie questions, I am working with a parent namespace Base and I include all my code within this namespace.
file model.js
Base = {}
Base.Observer = {
method1 : function(){//...},
method2 : function(){//...}
};
Base.Bot = function(name){
this.name = name;
this.somefunc = function(){};
}
file presenter.js
Base.Presenter = {
}
file helper.js
Base.Helper = { };
Now my problem is I would like to keep this module private. Without allowing any user access through any browser tools like firebug. So I could only think of wrapping them within a self executing anonymous function and making Base into a local variable which would lead to the presenter.js and helper.js not being able to access the Base namespace.
I would like to keep the files separate as it helps in keeping code organizated but I can't seem to figure what is the correct way to do this. Would appreciate any help on this.
Thank you
So I could only think of wrapping them within a self executing anonymous function and making Base into a local variable
That is the usual approach
which would lead to the presenter.js and helper.js not being able to access the Base namespace.
The function should return Base; which you then assign to a global.
See the module pattern
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.