Based on an answer I received in my previous question I would like to know how to simplify the following JavaScript pattern.
By simplifying I mean keeping it DRY by not repeating Module.*method.
ex.
Module.one = function() {
//one
};
Module.two = function() {
//two
};
This is how I believe it should look like:
Moduje.js
var Module = (function(Module) {
init = function() {
console.log("init");
};
return Module;
})(Module || {});
Module.Users.js
var Module = Module || {};
Module.Users = (function(Users) {
init = function() {
console.log("Module.Users.init");
};
return Module.Users;
})(Module.Users || {});
Here is the original code.
Moduje.js
var Module = (function(Module) {
Module.init = function() {
console.log("init");
};
return Module;
})(Module || {});
Module.Users.js
var Module = Module || {};
Module.Users = (function(Users) {
Users.init = function() {
console.log("Module.Users.init");
};
return Users;
})(Module.Users || {});
Well:
var Module = (function(Module) {
init = function() {
console.log("init");
};
return Module;
})(Module || {});
No, that won't work. You're creating the default value for "Module" outside that function. You've forgotten var in the declaration of "init" too, which in this case sort-of makes it work, but in a broken way (because it's a global variable, if not an error due to "strict" mode possibly being enforced). Since you're declaring "Module" with that statement, passing "Module" in as a (possible) argument doesn't make any sense.
I don't know what the word "simplify" means to you; the original looks OK to me.
edit — if what you'd like to do is get rid of repeated references to the base object, you can use an "extend" function, either from a library or that you write yourself:
function extend(target) {
var sources = Array.prototype.slice.call(arguments, 1), source;
for (var i = 0; i < sources.length; ++i) {
source = sources[i];
for (var key in source) {
if (source.hasOwnProperty(key))
target[key] = source[key];
}
}
return target;
}
Then you can do something like this:
var Module = createModule(); // make an object however you want
Module = extend(Module, {
newProperty_1: "hello world",
newProperty_2: function() {
// this will become a method on "Module"
},
newProperty_3: {
subObjectProperty: "whatever"
}
});
Related
I’ve been using the Javascript Revealing Module pattern a lot and I like the clear separation it gives between the public interface and the internals. However I keep running into a situation which makes me wonder if my overall usage pattern is correct, or if I should use some variant of the pattern.
The problem is when something passed into the init function of a module and stored privately for internal use also needs to be publicly exposed, either in a Knockout binding expression or some other module. The return statement of the module executes immediately and sometime later the init function is called, typically being passed some dynamic parameters such as Ajax URLs or raw JSON rendered in a script block within a Razor view. Because the module's return statement just returns a copy of the private variable rather than a reference, my setting that private variable in the init function can’t change what has already been returned.
var productsModule = function() {
var urls;
var init = function(ajaxUrls) {
urls = ajaxUrls;
};
return {
init: init,
urls: urls,
getUrls: function() { return urls; }
};
}();
var customersModule = function() {
var doSomethingWithProductsModule = function() {
alert(productsModule.urls); // undefined
alert(productsModule.getUrls()); // object
} ;
return {
doSomethingWithProductsModule: doSomethingWithProductsModule
};
}();
var urls = {
getProduct: '/Product/'
};
productsModule.init(urls);
customersModule.doSomethingWithProductsModule();
My workaround is just to wrap objects such as “urls” in a function and then access them via productsModule.getUrls(). However that becomes very messy, especially if the variable is a Knockout observable which is itself a function, and hence to evaluate it I need to use double brackets like productsModule.getMyObservable()().
Is there a nicer way to get at the up-to-date internal values using something which at least approximates the revealing module pattern?
Basic types are passed by value while objects are passed by reference; you could exploit this so that instead over overwriting urls in productsModule you just update it. This way the reference returned in the initial module invocation remains up to date. I've updated your code to show what I mean.
var productsModule = function() {
var urls = {};
var init = function(ajaxUrls) {
// Merge properties into the original object instead; more robust approach
// may be needed
for ( name in ajaxUrls ) {
if (ajaxUrls.hasOwnProperty(name)) {
urls[name] = ajaxUrls[name];
}
}
};
return {
init: init,
urls: urls,
getUrls: function() { return urls; }
};
}();
var customersModule = function() {
var doSomethingWithProductsModule = function() {
alert(productsModule.urls); // undefined
alert(productsModule.getUrls()); // object
} ;
return {
doSomethingWithProductsModule: doSomethingWithProductsModule
};
}();
var urls = {
getProduct: '/Product/'
};
productsModule.init(urls);
customersModule.doSomethingWithProductsModule();
Although I don't completely like the idea of having to iterate through all the possible levels of my objects to merge them like that, El Yobo's answer got me thinking about making the result of the module function itself a local variable whose properties I could update.
var productsModule = function() {
var urls;
var init = function(ajaxUrls) {
urls = ajaxUrls;
result.urls = urls;
};
var result = {
init: init,
urls: urls
};
return result;
}();
// Before init
alert(productsModule.urls); // undefined
var urls = {
getProduct: '/Product/'
};
productsModule.init(urls);
alert(productsModule.urls.getProduct); // /Product/
Why don't you make urls an observable property ?
Look at my example:
http://jsfiddle.net/Razaz/zkXYC/1/
var productsModule = function() {
var urls=ko.observable();
var init = function(ajaxUrls) {
urls(ajaxUrls);
};
return {
init: init,
urls: urls,
getUrls: function() { return urls(); }
};
}();
var customersModule = function() {
var doSomethingWithProductsModule = function() {
alert(productsModule.urls()); // undefined
alert(productsModule.getUrls()); // object
};
return {
doSomethingWithProductsModule: doSomethingWithProductsModule
};
}();
var urls = {
getProduct: '/Product/'
};
productsModule.init(urls);
customersModule.doSomethingWithProductsModule();
Greetings.
Ok this may be a noobolicious question as im new to OOP.
Im attempting to build something of a JS Object Library and was wondering if I could do it using nested functions??
var object = new function() {
this.action1 = function () {
this.dostuff1 = function () {
return "dostuff1";
};
this.dostuff2 = function () {
return "dostuff2";
};
};
I am having trouble accessing the third level functions. Can I nest like this?
this.action2 = function () {
return "action2";
};
alert(object.action1.dostuff2());
While Eberlin's answer is perfectly correct I'd suggest you to create a nested object which in turn again exposes functions rather than nesting functions itself. Otherwise this might become a maintainability nightmare.
Basically you could create
var Child = function(){
//constructor
};
Child.prototype.doStuff2 = function(){
return "dostuff2";
};
var Root = function(obj){
//constructor
this.child = obj;
};
Root.prototype.action1 = function(){
return "doStuff1";
};
//usage
var myRoot = new Root(new Child());
myRoot.action1();
myRoot.child.action2();
Here's a live example: http://jsbin.com/ijotup/edit#javascript,live
See below for some code cleanup:
var o = (new function () { // changed 'object' to 'o'
this.action1 = (function () { // added parentheses, not required.
this.dostuff1 = (function () { // does not return anything.
return "dostuff1"; // and is also not the proper way to organize
}); // ** look at the javascript prototype
return this; // now it does
}); // missing closing bracket
this.dostuff2 = (function () {
return "dostuff2";
});
});
alert(o.action1().dostuff2()); // action1 is a function, not a variable.
Hope this helps. Also, here's a brief tutorial on the javascript prototype.
I was reading about JavaScript Module pattern. My Question is how do I make submodules with it, i.e how can I inherit from it, say I have this class
var MODULE = (function () {
my = function(){
this.params = ""
},
privateVariable = 1;
my.prototype.moduleMethod = function () {
console.log("mod");
};
return my;
}());
How do I make a child class of it with properties inherited from parent? How can I do the same with module pattern?
The module pattern is not a class pattern. You cannot simply pretend you now have classes in JavaScript. As for inheritance, if you really need to inherit stuff, you should make an object via constructor function and use prototypal inheritance, although it's sometimes slower to execute.
As for creating a submodule it's simple
MODULE.submodule = (function(){
// another module stuff that can even reference MODULE
return { submodule: 'property' }
})();
Now, as for subclassing in the classical sense, you can simulate it on objects with prototypes, like Douglas Crockford does http://www.crockford.com/javascript/inheritance.html
For simulating it with modules, you can try by creating a seal/unseal functions inside the original module and use them in your submodules. You can check here http://www.pallavlaskar.com/javascript-module-pattern-in-details/
for the
Cloning and Inheritance
var MODULE_TWO = (function (old) {
var my = {},
key;
for (key in old) {
if (old.hasOwnProperty(key)) {
my[key] = old[key];
}
}
var super_moduleMethod = old.moduleMethod;
my.moduleMethod = function () {
// override method on the clone, access to super through super_moduleMethod
};
return my;
}(MODULE))
or the
Cross-File Private State
var MODULE = (function (my) {
var _private = my._private = my._private || {},
_seal = my._seal = my._seal || function () {
delete my._private;
delete my._seal;
delete my._unseal;
},
_unseal = my._unseal = my._unseal || function () {
my._private = _private;
my._seal = _seal;
my._unseal = _unseal;
};
// permanent access to _private, _seal, and _unseal
return my;
}(MODULE || {}));
> var MODULE = (function () {
> my = function(){
If my is not declared with var, it becomes global when the function executes. Also, by convention constructors have names starting with a capital letter, so:
var My = function(){
but you may as well just declare the function and be done with it:
function My() {
.
> this.params = ""
> },
> privateVariable = 1;
>
> my.prototype.moduleMethod = function () {
> console.log("mod");
> };
If you are just implementing prototype inheritance, why use the module pattern at all?
>
> return my; }());
The module pattern is not meant for inheritance but to create "modules" of functionality and emulate public, priveleged and private members to some extent.
What is the proper way to declare a namespace? I've just read "Developing Large Web Applications" and the author suggests using:
if (!window.YourNamespace) {
YourNamespace = {};
}
seems easy enough.. but I see all the javascript libraries for declaring namespaces and alternate methods. Isn't there a standard way to do this? Any problems with the above?
I've seen this convention used several places.
window.YourNamespace = window.YourNamespace || {};
The mentioned namespace-declarating-way by book author is indeed quite good one. But when you need to repeat it in several files and the namespace has several subnamespaces, it can get quite tedious:
if (!window.Foo) {
Foo = {};
}
if (!window.Foo.Bar) {
Foo.Bar = {};
}
if (!window.Foo.Bar.Baz) {
Foo.Bar.Baz = {};
}
etc...
Instead you should write a simple function that takes care of declaring the namespaces for you:
function namespace(ns) {
var parts = ns.split(/\./);
var obj = window;
for (var i=0; i<parts.length; i++) {
var p = parts[i];
if (!obj[p]) {
obj[p] = {};
}
obj = obj[p];
}
}
Now you can declare the whole nested namespace with just one line:
namespace("Foo.Bar.Baz");
In ExtJS framework this is basically what Ext.ns() function does. I don't really know about other libraries.
var Utils = {
namespace : function(name) {
return window[name] = window[name] || {};
}
};
or if you prefer your way use:
if (typeof window.YourNamespace === 'undefined') {
YourNamespace = {};
}
There is no standard way as you'll see between frameworks but they do go beyond the basics so that for example X.Y.Z, it will create all objects in that chain if they don't already exist.
bob.js handles namespaces like this:
bob.ns.setNs('YourNamespace', {
/*define your members here. e.g.:*/
method1: function () { /*...*/ }
});
// now, merge another, sub-namespace.
bob.ns.setNs('YourNamespace.YourSubNamespace', {
method2 function () { /*...*/ }
});
//call methods:
YourNamespace.method1();
YourNamespace.YourSubNamespace.method2();
Automating namespaces declaration in javascript is very simple as you can see:
var namespace = function(str, root) {
var chunks = str.split('.');
if(!root)
root = window;
var current = root;
for(var i = 0; i < chunks.length; i++) {
if (!current.hasOwnProperty(chunks[i]))
current[chunks[i]] = {};
current = current[chunks[i]];
}
return current;
};
// ----- USAGE ------
namespace('ivar.util.array');
ivar.util.array.foo = 'bar';
alert(ivar.util.array.foo);
namespace('string', ivar.util);
ivar.util.string.foo = 'baz';
alert(ivar.util.string.foo);
Try it out: http://jsfiddle.net/stamat/Kb5xY/
Blog post: http://stamat.wordpress.com/2013/04/12/javascript-elegant-namespace-declaration/
Some example of namespace function:
namespace = function(ns){
arr = ns.split(".")
parent = window
var temp
while( ( temp = arr.shift()) !== undefined){
parent[temp] = parent[temp] || {}
parent = parent[temp]
}
}
You can then use it as:
namespace("your.own.namespace")
your.own.namespace.Car= function () {
this.speed = 30;
}
I created a javascript class as follow:
var MyClass = (function() {
function myprivate(param) {
console.log(param);
}
return {
MyPublic : function(param) {
myprivate(param);
}
};
})();
MyClass.MyPublic("hello");
The code above is working, but my question is, how if I want to introduce namespace to that class.
Basically I want to be able to call the class like this:
Namespace.MyClass.MyPublic("Hello World");
If I added Namespace.MyClass, it'll throw error "Syntax Error".
I did try to add "window.Namespace = {}" and it doesn't work either.
Thanks.. :)
Usually I'd recommend doing this (assuming Namespace is not defined elsewhere):
var Namespace = {};
Namespace.MyClass = (function () {
// ...
}());
A more flexible, but more complex, approach:
var Namespace = (function (Namespace) {
Namespace.MyClass = function() {
var privateMember = "private";
function myPrivateMethod(param) {
alert(param || privateMember);
};
MyClass.MyPublicMember = "public";
MyClass.MyPublicMethod = function (param) {
myPrivateMethod(param);
};
}
return Namespace
}(Namespace || {}));
This builds Namespace.MyClass as above, but doesn't rely on Namespace already existing. It will declare and create it if it does not already exist. This also lets you load multiple members of Namespace in parallel in different files, loading order will not matter.
For more: http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth
YUI has a nice method for declaring namespaces
if (!YAHOO) {
var YAHOO = {};
}
YAHOO.namespace = function () {
var a = arguments,
o = null,
i, j, d;
for (i = 0; i < a.length; i = i + 1) {
d = ("" + a[i]).split(".");
o = YAHOO;
for (j = (d[0] == "YAHOO") ? 1 : 0; j < d.length; j = j + 1) {
o[d[j]] = o[d[j]] || {};
o = o[d[j]];
}
}
return o;
}
Place it above any function that you want to namespace like this:
YAHOO.namespace("MyNamespace.UI.Controls")
MyNamespace.UI.Controls.MyClass = function(){};
MyNamespace.UI.Controls.MyClass.prototype.someFunction = function(){};
This method is actually stand-alone and can easily be adapted to your application. Just find and replace "YAHOO" with your application's base namespace and you'll have something like MyOrg.namespace. The nice thing with this method is that you can declare namespaces at any depth without having to create object arrays in between, like for "UI" or "Controls"
A succinct way to do what you're asking is create "Namespace" as an object literal like this:
var Namespace = {
MyClass : (function() {
... rest of your module
})();
};
This could cause conflicts if you wanted to attach other details to Namespace in other files, but you could get around that by always creating Namespace first, then setting members explicitly.
Checkout the namespace library, it is very lightweight and easy to implement.
(function(){
namespace("MyClass", MyPublic);
function MyPublic(x){
return x+1;
}
})();
It supports automatically nesting as well
namespace("MyClass.SubClass.LowerClass", ....)
Would generate the necessary object hierarchy, if MyClass, SubClass did not already exist.
bob.js has nice syntax to define JavaScript namespace:
bob.ns.setNs('myApp.myMethods', {
method1: function() {
console.log('This is method 1');
},
method2: function() {
console.log('This is method 2');
}
});
//call method1.
myApp.myMethods.method1();
//call method2.
myApp.myMethods.method2();
(function($){
var Namespace =
{
Register : function(_Name)
{
var chk = false;
var cob = "";
var spc = _Name.split(".");
for(var i = 0; i<spc.length; i++)
{
if(cob!=""){cob+=".";}
cob+=spc[i];
chk = this.Exists(cob);
if(!chk){this.Create(cob);}
}
if(chk){ throw "Namespace: " + _Name + " is already defined."; }
},
Create : function(_Src)
{
eval("window." + _Src + " = new Object();");
},
Exists : function(_Src)
{
eval("var NE = false; try{if(" + _Src + "){NE = true;}else{NE = false;}}catch(err){NE=false;}");
return NE;
}
}
Namespace.Register("Campus.UI.Popup")
Campus.UI.Popup=function(){
defaults={
action:'',
ispartialaction:'',
customcallback:'',
confirmaction:'',
controltoupdateid:'',
width:500,
title:'',
onsubmit:function(id){
var popupid=id+"_popupholder";
if(this.ispartialaction){
$.ajax({
url:this.action,
type:"Get",
context:this,
success:function(data){
$('#'+id).parents('body').find('form').append("<div id'"+popupid+"'></div>");
var ajaxContext=this;
$("#"+popupid).dialog({
autoopen:false,
model:true,
width:this.width,
title:this.title,
buttons:{
"Confirm":function(){
if(ajaxContext.customcallback==''){
var popupform=$(this).find("form");
if(popupform.isValid()){
$.post(ajaxContext.confirmaction,popupform.serialize(),function(d){
if(d!='')
{
$.each(d.Data,function(i,j){
switch(j.Operation)
{
case 1:
if($('#'+j.ControlClientID).is("select"))
{
$('#'+j.ControlClientID).val(j.Value);
$('#'+j.ControlClientID).change();
}
else if($('input[name="'+j.ControlClientID+'"]').length>0)
{
$('input[name="'+j.ControlClientID+'"][value="'+j.Value+'"]').prop("checked",true);
}
break;
case 2:
if($('#'+j.ControlClientID).is("select"))
{
$('#'+j.ControlClientID).append("<option selected='selected' value=\""+j.Value+"\">"+j.Text+"</option>");
}
else
{
var len=$('input[name="'+j.ControlClientID+'"]').length;
$('#'+j.ControlClientID+"list").append('<li><input type="checkbox" name="'+j.ControlClientID+'" value="'+j.Value+'" id="ae'+j.ControlClientID+len+'"/><label for "ae'+j.ControlClientID+len+'">'+j.Text+'</label>');
}
break;
case 0:
$('#'+j.ControlClientID).val(j.Value);
breakl
default:break;
}
});
popupform.parent().dialog("destroy").remove();
$("#"+ajaxContext.controltoupdateid).change();
}
});
}
}
else
{
executeByFunctionName(ajaxContext.customcallback,window,new Array());
}
},
"Cancel":function(){
$(this).dialog("close");
}
}
});
$("#"+popupid).dialog("open");
$("#"+popupid).empty().append(data);
},
error:function(e)
{
alert(e);
}
});
}
else
{
var frm=document.createElement("form");
frm.id="CampusForm";
frm.name="CampusForm";
frm.action=this.action;
frm.method="post";
var arr=$($("#"+id).closest("body").find("form")).serializeArray();
$.each(arr,function(i,j){
var hidd=document.createElement("input");
hidd.type="hidden";
hidd.name=j.name;
hidd.value=j.value;
frm.appendChild(hidd);});
document.appendChild(frm);
frm.submit();
}
}
},
clicksubmit=function(){
var opts=$(this).data("CampusPopup");
opts.onsubmit($(this).attr("id"));
return false;
};
return
{
init:function(opt){
var opts=$.extend({},defaults,opt||{});
$(this).data('CampusPopup',opts);
$(this).bind("click",clicksubmit);
}};
}();
$.extend({CampusPopup:Campus.UI.Popup.init});
})(jQuery)
Automating namespaces declaration in javascript is very simple as you can see:
var namespace = function(str, root) {
var chunks = str.split('.');
if(!root)
root = window;
var current = root;
for(var i = 0; i < chunks.length; i++) {
if (!current.hasOwnProperty(chunks[i]))
current[chunks[i]] = {};
current = current[chunks[i]];
}
return current;
};
// ----- USAGE ------
namespace('ivar.util.array');
ivar.util.array.foo = 'bar';
alert(ivar.util.array.foo);
namespace('string', ivar.util);
ivar.util.string.foo = 'baz';
alert(ivar.util.string.foo);
Try it out: http://jsfiddle.net/stamat/Kb5xY/
Blog post: http://stamat.wordpress.com/2013/04/12/javascript-elegant-namespace-declaration/
This is the design pattern I use which allows for nested namespaces as well as adding to the namespace later (even from a separate JS file) so you don't pollute the global namespace:
Example: JsFiddle
(function ($, MyObject, undefined) {
MyObject.publicFunction = function () {
console.log("public");
};
var privateFunction = function () {
console.log("private");
};
var privateNumber = 0;
MyObject.getNumber = function () {
this.publicFunction();
privateFunction();
privateNumber++;
console.log(privateNumber);
};
// Nested namespace
MyObject.nested = MyObject.nested || {};
MyObject.nested.test = function (text) {
console.log(text);
};
}(jQuery, window.MyObject = window.MyObject || {}));
// Try it
MyObject.getNumber();
MyObject.nested.test('Nested');
Here is how to add to MyObject from another JavaScript file:
(function ($, MyObject, undefined) {
MyObject.newFunction = function () {
console.log("Added");
};
}(jQuery, window.MyObject = window.MyObject || {}));
// Pass `jQuery` to prevent conflicts and `MyObject` so it can be added to, instead of overwritten
This resource helped me learn all about the different JS design patterns: http://addyosmani.com/resources/essentialjsdesignpatterns/book/
To create new JavaScript namespaces (like Math), I personally define the following base class that can be extended, but not instantiated:
class Namespace {
constructor() { throw TypeError("cannot instantiate a namespace") }
}
Subclasses will inherit constructor or override it with a method that calls super, so instantiation results in a TypeError either way.
The actual namespaces are defined by extending Namespace with any number of static properties (which can reference one another):
class ASCII extends Namespace {
static whitespace = "\t\n\r\v ";
static digits = "0123456789";
static uppers = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
static lowers = ASCII.uppers.toLowerCase();
static alphas = ASCII.uppers + ASCII.lowers;
static alphanumerics = ASCII.alphas + ASCII.digits;
}
const isDigital = candidate => ASCII.digits.includes(candidate);
The example use a bunch of string constants, but a namespace can contain any types of value, including functions (defined as static methods).