Point of module pattern? - javascript

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.

Related

node "require" hoisted to top outside of script -- loses access to variables from outer function

I'm requiring different files at the top of my main script in node. All my require statements are hoisted to the top. This creates a problem because when the methods within those imported scripts are invoked they do not have access to the function within which they are invoked (Because they are inevitably defined outside those functions due to the hoisting issue). Therefore, I must always pass variables in an options object. Has anyone experiences a similar issue? Is there some sort of standard workaround that people use? Thanks!
function outer(){
//let's pretend we're in a node environment
//this required script will get hoisted to the very top and therefore lose access to the "something" variable!
var common = require('../globals/common.js');
var something = "something";
common.printsomething();//will return "something is not defined"
};
outer();
Hm.
I would assume that it'd ultimately be better to pass 'something' to the printsomething method, like so.
common.printfoo('bar'); //returns 'bar'
Typically, what you're doing there isn't how modules in node works. Yes, breaking up a large program into separate files is an excellent way to organize a project, but I'm afraid that I have to say you're doing it wrong here. In the context of 'outer', you could do:
/*script.js*/
var common = require('../globals/common.js');
function outer(str){
common.printsomething(str);//will return "something"
};
var something = 'something';
outer(something);
/*common.js*/
function printthing(str){
console.log(str);
}
module.exports = {
printsomething: function(str){
printthing(str)
}
}
module.js:
module.exports.print = function (data) {
console.log(data);
}
module.exports.add = function (a, b, callback) {
callback(a + b);
}
main.js
var mymodule = require('module');
module.print('Some data'); //Will print "Some data" in the console
module.add(25, 12, function (result) {
console.log(result); //Will print 37
});
As you can see, in main.js, I do not need to know the content of module.js to wrk. that is the goal of modules: put the hard logic somewhere else, to build better code. Modules like async or fs are huge and complex, but I just have to import them to work with it, and don't need to know how it does it.
While building your own module, think of it as a new library of tools, so that you can reuse it in another project without the need to set specific variables to use them. Imagine the chaos it would be if two module were able to get the content of your var something for unrelated goal!
Modules are self contained, to be reusable. A "de hoisting" of thoses would reduce their efficacity.
EDIT:
If you have a lot of environment variable, you can try a pattern where you set them once inside the module, but you have to make sure to provide a way to interact with them.
module:
var data = {};
function set(key, value) {
data[key] = value;
}
function get(key) {
return data[key];
}
function print(key) {
console.log(data[key]);
}
function add(keyA, keyB) {
return data[keyA] + data[keyB];
}
module.exports = {
set: set,
get: get,
print: print,
add: add
};
main.js
var mymod = require('mymod');
mymod.set('data', 'something');
mymod.set('a', 25);
mymod.set('b', 12);
mymod.print('data'); //Print "something"
var c = mymod.add('a', 'b');
console.log(c); //Print 32

Javascript module pattern - Can all modules access eachother?

I've done a fair amount with vanilla javascript and jquery. I'm trying to write an app now that uses some form of closures to privatize methods so that everything isn't just out in the public namespace.
I turned to the Module Pattern, because it seemed to be the solution to my problems, however I can't quite wrap my head around it. When you use this pattern to add methods onto the main app, can all of the modules use all of the methods from other modules too? Because, it seems like that is not the case.
var MODULE = (function () {
var my = {},
privateVariable = 1;
function privateMethod() {
// ...
}
my.moduleProperty = 1;
my.moduleMethod = function () {
console.log("Method 1!");
};
my.anotherMethod(); //This doesn't work. anotherMethod() not defined
return my;
}());
var MODULETWO = (function (my) {
my.anotherMethod = function () {
console.log("Method 2!");
};
my.moduleMethod();
my.anotherMethod();
return my;
}(MODULETWO));
For some reason I would expect the commented method to work. Can we make that work? I envision having an app.js with the meat of an app, with other separate js files that have utility functions to help that app, but in a lot of cases I envision those utility classes needing access to the main app's scope. I can't seem to get that...
Thoughts?
Someone I talked to pointed me to Browserify.js, but I don't know if that solves my requirement of having everything inaccessible via closures. It seems just like a bundling app.
Your problem is that you don't adhere to Object Oriented Design rules. There are various paradigms to this, and more books, blogs and videos then you could consume in 10 lifetimes. Personally I recommend the SOLID principles for OOP.
More specifically, your modules should serve as encapsulated units. A module should have a single logical responsibility that should be exposed through its public methods. If you need access to its private methods, you have a design problem.
The adhoc module pattern gives you a way to create privacy by enclosing a value inside of a function, thus a closure.
Think of it this way:
If you declare a variable inside a function, it can only be accessed in that function, unless you expose it.
Unexposed, _foo just sits there waiting for garbage collection
var foo = function() {
_foo = {name: 'joe', age: 42};
};
var myFoo = new foo();//this is undefined as we return nothing
Exposed, name is exposed but age is not, you can't access _foo directly. In the code below age is useless because it can't be reached.
var foo = function() {
_foo = {name: 'joe', age: 42};
var api = {
getName: function() {
return _foo.name;//api can return this because _foo is still in scope
}
};
var myFoo = new foo();//this is an object with one method, getName (it is the api returned from foo).
If you create another constructor, bar, it will not be able to interact with _foo, since it is trapped inside of myFoo. bar's api can only access variables defined inside of it, in this case _bar.
var bar = function() {
_bar = {name: 'mike', age: 4};
var api = {
getName: function() {
return _foo.name;
},
getAge: function() {
return _bar.age
hasBirthday: function() {
_bar.age++;
return _bar.age;//bumps the age and returns the new age.
}
};
Notice bar takes full advantage of the private data, it might be a good idea to add setters.
This pattern provides privacy, the architecture of how you structure your app is totally up to you.
Check out this book for comprehensive examples of fundemental Javascript patterns: https://addyosmani.com/resources/essentialjsdesignpatterns/book/

Javascript Module Pattern Uncaught Reference Error

I've been following this tutoral, and when referencing Module as an argument in ModuleTwo, everything works fine until I comment out Module.
My understanding is that the double pipes || and empty object {} will create an empty object in place of Module if it's undefined, but instead I'm getting an error in the console.
var Module = (function () {
var privateMethod = function () {
// private
};
var someMethod = function () {
// public
};
var anotherMethod = function () {
// public
};
return {
someMethod: someMethod,
anotherMethod: anotherMethod
};
})();
var ModuleTwo = (function (Module) {
Module.extension = function () {
// another method!
};
return Module;
})(Module || {});
Basically, there’s an error in the tutorial. One way to make things work was suggested by rplantiko, but it might be easier to just write window.Module || {} instead of Module || {}.
How things work here:
Accessing a non-existent property of any object yields undefined. However, referencing a variable that hasn’t been declared yields ReferenceError (so your understanding was a little bit off there).
Browser puts all global variables as properties onto global window object. Module in the tutorial is a global variable, because it’s declared outside all functions, so you can access it via window.Module, which will not cause ReferenceError if undefined (per previous point).
It might be a good practice to explicitly assign to window any global variable you define (e.g., do window.Module = (function () { … if you intend to make Module global), but that’s arguable and out of scope of this discussion.
When you apply the function defining your 2nd module to (Module || {}), the symbol Module cannot be resolved if the Module hasn't been declared earlier, which always gives a JavaScript error. If you want the 2nd Module to be defined even in the absence of the first Module, try the following:
var ModuleTwo = (function(Module) {
...
})(typeof Module == 'object' ? Module : {} );

What is meant by “leaking” into global scope?

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.

Annotate Singleton objects in JavaScript for the Google Closure Compiler, or "dangerous use of the global this object" warning

I'm working with the Google Closure Compiler in ADVANCED_OPTIMIZATIONS compilation level and have started to annotate my constructors because I get all kinds of warnings:
WARNING - dangerous use of the global this object
For my 'constructor' type functions I'll annotate them like this:
/**
* Foo is my constructor
* #constructor
*/
Foo = function() {
this.member = {};
}
/**
* does something
* #this {Foo}
*/
Foo.prototype.doSomething = function() {
...
}
That seems to work fine, however what if I have a 'singleton' object that isn't constructed with var myFoo = new Foo();
I couldn't find in the documentation how to annotate this type of object because its type is just object right?
Bar = {
member: null,
init: function() {
this.member = {};
}
};
The preferred way of creating singletons in Closure is like this:
/** #constructor */
var Bar = function() { };
goog.addSingletonGetter(Bar);
Bar.prototype.member = null;
Bar.prototype.init = function() {
this.member = {};
};
This allows for lazy instantiation of the singleton. Use it like this:
var bar1 = Bar.getInstance();
var bar2 = Bar.getInstance();
bar1.init();
console.log(bar2.member);
Keep in mind that this doesn't prevent people from using the constructor to create instances of Bar.
This is exactly the type of potential bug that "dangerous use of this" warns you against. In your example, the Closure Compiler may try to "flatten" your code to:
Bar$member = null;
Bar$init = function() { this.member = {}; };
NOTE: The Closure Compiler currently will not flatten a namespace that is declared as a global object (i.e. without the "var" keyword in front), so your code may still work now. However, there is no telling that it won't do that in a future version and your code will suddenly break without warning.
Of course, then "Bar$member" and "Bar$init" will be renamed to "a" and "b" respectively. This is called "namespace flattening" or "collapsing of properties".
You can immediately see that your code no longer works correctly. Before compilation, if you write:
Bar.init();
this will refer to Bar. However, after compilation it becomes:
Bar$init();
this will no longer refer to Bar. Instead it refers to the global object.
This is way the compiler is trying to warn you that using "this" in such a way is "dangerous", because "this" may be changed to refer to the "global" object. That's the true meaning of the warning.
In short, DO NOT DO THIS. This type of coding style creates bugs that are very difficult to track down.
Modify your code this way:
var Bar = { // Closure Compiler treats globals and properties on global differently
member: null,
init: function() { Bar.member = {}; }
};
or use a closure:
var Bar = (function() {
var member = null;
return {
init: function() { member = {}; }
};
})();
When using the Closure Compiler in Advanced Mode, do not try to get rid of warnings by annotating them away. Warnings are there for a reason -- they try to warn you about something.

Categories

Resources