I am trying to organize my JavaScript better. My goal is to have modular architecture that I can break into separate files (sitename.js, sitename.utils.js etc).
I'd like to know what are advantages and disadvantages of these two patterns and which one is more suitable for breaking into modules that live in separate files.
PATTERN #1 (module pattern)
var MODULE = (function () {
//private methods
return {
common: {
init: function() {
console.log("common.init");
}
},
users: {
init: function () {
console.log("users.init");
},
show: function () {
console.log("users.show");
}
}
}
})();
PATTERN #2 (singleton)
var MODULE = {
common: {
init: function() {
console.log("common.init");
}
},
users: {
init: function() {
console.log("users.init");
},
show: function() {
console.log("users.show");
}
}
};
Personally, I recommend an extension of #1, as follows:
var Module = (function(Module) {
// A comment
Module.variable1 = 3;
/**
* init()
*/
Module.init = function() {
console.log("init");
};
// ...
return Module;
})(Module || {});
I like this pattern for a couple reasons. One, documentation (specifically javadoc-style) look more natural when all your functions are declarations rather than a big hash. Two, if your submodules grow in size, it lets you break them into multiple files without any refactoring.
For example, if Module.Users were to go into its own file:
var Module = Module || {};
Module.Users = (function(Users) {
/**
* init()
*/
Users.init = function() {
console.log("Module.Users.init");
};
// ...
return Users;
})(Module.Users || {});
Now "module.js" and "module.users.js" can be separate files, and they'll work regardless of the order they are loaded. Also note the local scoping of the module name - this is very handy if your module name is long, because you can take "MyApp.Users.EditScreen" and refer to it with a variable like "ES" within the scope of your module definition.
The first pattern allows for private variables, methods, etc via closures. For example:
var MODULE = (function () {
var privateStuff = 'This is private';
var doStuff = function(obj) {
console.log('Doing stuff...');
console.log(privateStuff);
};
return {
common: {
init: function() {
console.log("common.init");
doStuff(this);
}
},
users: {
init: function () {
console.log("users.init");
},
show: function () {
console.log("users.show");
}
}
}
})();
privateStuff and doStuff are not properties of the object, and are not available to anything but what's defined inside the function that returns MODULE. So showing an example for how to do this with #2 is not possible.
JS doesn't have the concept of private members, so you can't define them via a regular object literal. So if you need private stuff, go for the first option. If you don't, though, #2 is simpler.
Your code as written is pretty much the same. However, the first form is much easier to work with as you evolve your code, because it allows you to add private variables and functions. The second form doesn't support this, and you nearly always end up wanting the first form eventually.
Related
I have my javascript code as follow:
$(document).ready(function () {
//call of global functions
globalFunction1();
globalFunction2(); //create a new object inside
globalFunction3();
}
function globalFunction1() {
// do something directly with jquery selectors
var testObj1 = new object1($('#tree')); // this is called later in the function
testObj.doSomething();
}
function globalFunction2() {
// do other things
}
function globalFunction3() {
// do something directly with jquery selectors
}
//creating an object in js
var object1 = (function () {
var tree;
function object1($tree) {
tree = $tree;
});
}
object1.prototype.doSomething = function () {
.....
};
return fancyStructure;
})();
Normally I have more global functions and if possible I always try to create objects using the new keyword (as in Java or C#)
Now, I am asked to provide namespacing in order to avoid function conflict problems. Thing is I am not sure how to achieve that giving my current code and knowing that I need to keep the code Object Oriented.
Hence, I am wondering if there is a way to add some namespacing effisciently. Any suggestion will do as long as it is along the lines of adding a namespace.
Just put your functions into an Object:
var mynamespace = {
globalFunction1 : function() {
// do something directly with jquery selectors
var testObj1 = new object1($('#tree')); // this is called later in the function
testObj.doSomething();
},
globalFunction2 : function() {
// do other things
},
globalFunction3 : function() {
// do something directly with jquery selectors
}
}
and call the functions with
mynamespace.globalFunction1();
Or you could just define your namespace
mynamespace = {};
And later add the the functions with
mynamespace.globalFunction1 = function() {
//do something
};
Use objects as containers for your functions. This is the standard approach of code structuring in JS.
var namespace1 = {
func1: function() {},
func2: function() {},
}
var namespace2 = {
func1: function() {},
func2: function() {},
}
namespace1.func2();
You can store your OOP code in this namespaces:
var namespace3 = {
someObj: function() {},
create: function() { return new this.someObj(); },
}
namespace3.someObj.prototype = {
count: 15,
someFunc() {}
}
And you can easily extend them:
namespace3.anotherObj = function () {}
Edit
Regarding your example:
var fancyStructureWrapped = (function () {
var tree;
function fancyStructure($tree) {
tree = $tree;
});
fancyStructure.prototype.doSomething = function () {
.....
};
return fancyStructure;
})();
// add it to some namespace
someNamespace.fancyStructure = fancyStructureWrapped;
//create an instance
var fs = new someNamespace.fancyStructure();
//and use it
fs.doSomething();
If you're looking for a general approach to managing a growing JavaScript codebase, check out RequireJS and/or Browserify. Both are libraries that allow dividing your code up into modular bits (ie. AMD or CommonJS modules) and then referencing/importing between them. They include tooling for bundling these files into a single JS file when it's time to deploy a production build too.
Having a project where I have speed coded up some core functionality I would like to split it up into modules. My struggle now is how to combine prototypes from one to the next. My idea is something like this:
(function (window) {
/* Code for base module with core functions. */
function CORE () {
}
window.CORE = CORE; /* I use different naming in real code ... */
})(window);
(function (CORE) {
/* Code for module with extending functionality. */
function MODULE1 () {
}
CORE.MODULE1 = MODULE1;
})(window.CORE);
I use an approach for creation as something like:
(function (window) {
var Core = function (options) {
return new Core.prototype.init(options);
}
Core.prototype = {
init : function (options) {
this.a = options.a;
return this;
}
}
Core.prototype.init.prototype = Core.prototype;
Core.prototype.init.prototype.fun1 = function () { }
Core.prototype.init.prototype.fun2 = function () { }
...
window.Core = Core; /* Optionally = Core.init */
})(window);
And then a module like:
(function (Core) {
var Module1 = Core.Module1 = function (options) {
return new Module1.prototype.build(options);
}
Module1.prototype = {
build : function (options) {
this.a = options.a;
return this;
}
}
Module1.prototype.build.prototype = Module1.prototype;
Module1.prototype.build.prototype.fun1 = function () { }
Module1.prototype.build.prototype.fun2 = function () { }
...
Core.Module1 = Module1;
Core.Module1_XO = Module1.prototype.build;
})(window.Core);
Now a print of toString() of Core, Core.Module1 and Core.Module1_XO all yield their respective code. But there is no binding as in:
If I say:
var obj = Core({...}); , OK.
obj.Module1({...}), Fail. Object #<Object> has no method Module1
new obj.Module1_XO({...}), Fail. undefined is not a function
Core.Module1({...}), OK, but looses prototypes from Core.
new Core.Module1_XO({...}), OK, but looses prototypes from Core.
...
One way that seem to work is by updating Core by a bind function as in:
var obj = Core({...});
var mod1 = Core.Module1({...}, obj); <-- pass obj
// In Module1 constructor:
build : function (options, ref) {
this.a = options.a;
ref.bind("Module1", this);
}
// And In Core:
Core.prototype.bind(which, what) {
this[which] = what;
}
Question is how I can update Core with Module without this hack. Why doesn't Core become updated by:
window.Core.Module1 = Module1;
Is it hidden from Core?
I have also tried to bind in outer scope of module as in:
(function (Core) {
/* ... code ... for Mudule1 */
Core.bind("Module1", Module1);
}(window.Core);
But this fails as well. Core does not get updated with methods from Module.
Here is a scramble of a fiddle I have messed with, (Note that the printed text is in reverse (prepended) not appended such as newest on top.). It is not the most tidy code, and It is in midts of edits. (I try new approaches frequently.)
What you're doing right now is problematic for several reasons:
You're adding a module to the constructor (type) and not the objects.
Global state here - everyone gets one Module1.
My suggestion would be using a generic version of the builder pattern (or even a mediator).
Here is what it might look like.
Core = (function Core(){
var modules = [];
return {
setModule : function(name,value){
modules.push({name:name,value:value});
},
build : function(options){
this.a = options.a;
// now let's add all modules
modules.forEach(function(module){
this[module.name] = new module.value();
});
}
};
});
Usage would be something like:
var app = new Core.build({a:"foo"});
app.a;//"foo"
If you want to add a module it'd be something like
function Module1(){
this.name = "Zimbalabim";
}
Core.setModule("Module1",Module1);
var app = new Core.build({a:"Bar"});
app.Module1.name;//"Zimbalabim"
app.a;//"Bar"
Or course, a more generic architecture would allow creating different apps with different architectures (with dependency injection containers probably) but let's not go that far yet :)
Say I have the following modules, split across multiple files both capable of extending skillet:
File1.js:
(function(){
var privateVar1 = 0;
var privateFunction1 = function() {
//function definiton
};
skillet.fry() = function() {
//fry it
//matchbox.light();
};
})(window.skillet = window.skillet || {});
File2.js:
(function(){
var privateVar2 = 0;
var privateFunction2 = function() {
//some private function
};
skillet.grillIt = function() {
//grill It
//matchbox.strike(); <-- Shared with File1.js
};
})(window.skillet = window.skillet || {});
Is it possible to have a shared variable/object like matchbox be sharable by the two modules without being bound to window.matchbox or window.skillet.matchbox? I.e. the visibility of matchbox should only be to File1.js and File2.js and must not be accessible elsewhere. I doubt if it's possible, but is there a way to achieve such a behavior in JavaScript? If not, what's the best practice to use in this regard?
(It's more like having a shared event-bus among a set of related modules without exposing that bus globally)
Nope.
"private" variables work in JS only because of the scope that the function was declared in. There is no way to share that scope with a function declared in an entirely different scope. Scope is an unchangeable property of functions, once they are created.
This is why this sort of thing is usually done with _foo style properties.
skillet._matchbox = { strike: function() { ... } };
The underscore prefix is convention for "internal" and serves as a hint not to mess with it.
You could also get creative with how you pass matchbox around though, though in all cases it will mean providing a way to get matchbox out it's original scope. Like perhaps, makes a skillet.extend method that passes the matchbox to it's argument?
(function() {
var matchbox = { strike: function() { ... } }
window.skillet = {
extend: function(fn) {
fn(matchbox);
}
};
})();
skillet.extend(function(matchbox) {
var privateVar2 = 0;
var privateFunction2 = function() {};
skillet.grillIt = function() {
//grill It
matchbox.strike();
};
}
Which allows you to use matchbox outside it's original scope in a controlled way. But it also allows anyone to get matchbox that maybe shouldn't.
var stolenMatchbox;
skillet.extend(function(matchbox) {
stolenMatchbox = matchbox;
});
while (stolenMatchbox.count > 0) { stolenMatchbox.strike(); }
alert("Now you are outta matches, sucker!");
Since you are already dividing your code into multiple files, you may look into using a module loader like require.js. You could define a third module for the matchbox and then pass it in as an argument to the two skillets in your example above. With this approach, you won't have to globally expose the matchbox via the window.
File1.js with require.js would look like this:
define(['matchbox'], function(matchbox){
(function(){
var privateVar1 = 0;
var privateFunction1 = function() {
//function definiton
};
skillet.fry() = function() {
//fry it
matchbox.light();
};
})(window.skillet = window.skillet || {});
});
matchbox.js would look something like this:
define([], function() {
function light() {
//light implementation
}
function strike() {
//strike implementation
}
return {
light: light,
strike: strike
}
}
I have been writing a lot of javascript functions and event listeners and I want to move them into their own namespaced, isolated place that doesn't conflict when I concatenate and minify it with my other javascript files.
I am still new to javascript, so there may be simple solution to this answer. I started by creating a javascript object:
var MySpecialStuff = {
init: function(){
//do everything here
}
};
Then in my html, on the page I want to use it on I can initialize this code:
<script>
MySpecialStuff.init();
</script>
But then the init method started growing and I need to start breaking that code into smaller chunks, but I am stuck on the syntax and how to set private methods/variables and call them from within the init method and other private methods. How can I do this?
Am I headed in the right direction? What other ways can I / should I go about doing this sort of thing?
You are headed in the right direction. You can use the module pattern to create an object with private members and methods like this:
var foo = function(){
var bar = ""; //private
function funk(){
//private function
return "stuff";
}
return{
getBar: function(){
return bar;
},
init: function(){
alert(funk());
},
randomMember: 0 //public member
}
}();
Only what's in the return block is public, but you can call any private methods/access any private methods from within the return block.
Thanks to Joseph for linking to another SO question which explained this approach:
Another way to do it, which I consider to be a little bit less restrictive than the object literal form:
var MySpecialStuff = new function() {
var privateFunction = function() {
};
this.init = function() {
};
};
I like to further segment my code into a more modular approach. So, let's say we have a page that has a list of blog posts, a page menu, and a sidebar. I'd end up with this:
var blog_controller = {
init: function(){
document.getElementById('some_element').addEvent('click', this.handleSomeClick);
this.applySomePlugin();
},
applySomePlugin: function () {
/* do whatever needs to happen */
},
handleSomeClick: function () {
// scope will be element
this.style.color = 'red';
}
};
var page_menu_controller = {
init: function(){
document.getElementById('some_other_element').addEvent('click', this.handleSomeClick);
},
handleSomeClick: function () {
// scope will be element
this.style.color = 'blue';
}
};
... and so on. This keeps code organized by purpose, helps keep scope clear, and allows you to reuse elements of code that might occur frequently (for instance, if you AJAX'd in a new blog post, you could call this.applySomePlugin again).
This of course is a quick-and-dirty example, but I hope you get the idea
Divide responsibility of code you have put inside the init function into subobjects of the main object.
MySpecialStuff = {
// Variables/constants and everything else that needs to be accessed inside the whole MySpecialStuff object
init: function(){
//Do only whats required to be globally initiated.
this.MainMenu.init(); // Main menu stuff usually is.
}
};
MySpecialStuff.MainMenu = {
// Variables / constants that are only important to the MainMenu subobject.
init: function(){
//Just the initiation stuff thats related to the MainMenu subobject.
}
};
MySpecialStuff.SlideShow = {
// Variables / constants that are only important to the SlideShow subobject.
init: function(){
// Same as for the MainMenu with the difference that nonessential objects can be "fired" when required
}
};
I'm new to javascript namespaces, and I found myself kinda deep within a namespace, but unable to find a way to navigate from within the namespace to another object in the same general namespace. It's best described by the code below:
$.fileUploading = {
images: {
settings: {
// How do you do this?
bing_bong: find.a.way.to.functionOne
},
functionOne: function() { return "Rock!"; }
}
}
Is there a way to do that?
Because namespaces are just properties on objects, there's no way to find out what object a property belongs to, from the property. A simple reason is that an identical property can appear in multiple objects.
Namespaces are supposed to be stable and constant, so there's nothing wrong with referencing the entire thing. However, if you need to access the same names a ton of times, you could make it a bit easier for yourself by assigning it to a variable.
var my_ns = $.fileUploading;
This would work:
$.fileUploading = {
images: {
settings: {},
functionOne: function() { return "Rock!"; }
}
};
$.fileUploading.images.settings.bing_bong = $.fileUploading.images.functionOne;
This also:
function f() { return "Rock!"; }
$.fileUploading = {
images: {
settings: {
// How do you do this?
bing_bong: f
},
functionOne: f
}
};
(function(){
var yourNameSpace={
publicProp1:publicFn1,
publicProp2:publicFn2,
publicProp3:publicFn3
};
window.yourNameSpace = yourNameSpace;
//private variable
var _privateVar1,_privateVar2,_privateVar3;
//privatefns
function _privateFn1(){}
function _privateFn2(){}
function _privateFn3(){}
function _privateFn4(){}
//public functions can access private fns
function publicFn1(){}
function publicFn2(){}
function publicFn3(){}
}(undefined);