Sharing variables in JavaScript Namespace - javascript

My Goal: To namespace my javascript to keep the global namespace clean.
My question: how do I share variables between methods in my JavaScript namespace?
In my example I am extending and overwriting the behaviour of the ASP.net ModalPopupExtender. I want to know how I can share the modalPopupStack variable with ModalPopupShowOverride and ModalPopupHideOverride without making it global.
Relevant code:
$(function () {
if (Sys.Extended != undefined && Sys.Extended.UI != undefined && Sys.Extended.UI.ModalPopupBehavior != undefined) {
MyPageMethods.ModalPopupShowOriginal = Sys.Extended.UI.ModalPopupBehavior.prototype.show;
MyPageMethods.ModalPopupHideOriginal = Sys.Extended.UI.ModalPopupBehavior.prototype.hide;
Sys.Extended.UI.ModalPopupBehavior.prototype.show = MyPageMethods.ModalPopupOverrides.ModalPopupShowOverride;
Sys.Extended.UI.ModalPopupBehavior.prototype.hide = MyPageMethods.ModalPopupOverrides.ModalPopupHideOverride;
}
});
var MyPageMethods = {
ModalPopupShowOriginal: function () { },
ModalPopupHideOriginal: function () { },
ModalPopupOverrides: {
modalPopupStack: new Array(),
ModalPopupShowOverride: function () {
var extender = this;
var topElement;
MyPageMethods.ModalPopupShowOriginal.apply(this, arguments);
for (var x = 0; x < modalPopupStack.length; x++) {
if ($(modalPopupStack[x].background).css("z-index") > $(extender._element).css('z-index') || $(modalPopupStack[x].popup).css("z-index") > $(extender._element).css('z-index')) {
if ($(modalPopupStack[x].background).css("z-index") > $(extender._element).css('z-index')) {
topElement = $(modalPopupStack[x].background).css("z-index");
}
else if ($(modalPopupStack[x].popup).css("z-index") > $(extender._element).css('z-index')) {
topElement = $(modalPopupStack[x].popup).css("z-index");
}
}
}
if (topElement != undefined) {
$(extender._backgroundElement).css('z-index', topElement);
}
modalPopupStack.push({ 'id': extender._id, 'background': extender._backgroundElement, 'popup': extender._element });
},
ModalPopupHideOverride: function () {
var extender;
MyPageMethods.ModalPopupHideOriginal.apply(this, arguments);
extender = modalPopupStack.shift();
}
}
}
I'm sure there is a simple solution to this, but I'm not sure what it is.

It sounds like you want the variables to be visible within your namespace but not outside of it. If so then try the following solution.
var MyPageMethods = (function() {
// This variable is local to the namespace. It can't be accessed from
// the caller
var modalPopupStack = new Array();
// These values are available to the callers as members of MyPageMethods
return {
ModalPopupShowOriginal: function () { },
ModalPopupHideOriginal: function () { },
ModalPopupOverrides: { ... }
};
})();
This pattern uses a function to establish a private function scope for local variables of the namespace. It then returns a new object which contains the members accessible outside the namespace. Those definitions occur inside the function hence they can access the namespace private data.

You can reference that property in both methods using:
MyPageMethods.ModalPopupOverrides.modalPopupStack
That can be a little bit cumbersome, so you'd likely want to alias it inside each method, like this:
var modalPopupStack = MyPageMethods.ModalPopupOverrides.modalPopupStack;
Note that the value is still visible in the global scope (unlike in #JaredPar's answer), but its merely piggy-backing on an existing global object.

Make it part of the namespace, if you like. Or for more privacy, make a local closure which incorporates it and exposes the functions you want:
var MyPageMethods = {
ModalPopupShowOriginal: function () { },
ModalPopupHideOriginal: function () { },
ModalPopupOverrides: (function() {
var modalPopupStack = new Array();
var show = function () {
// show implementation using modalPopupStack
};
var hide = function () {
// hide implementation using modalPopupStack
};
return {
ModalPopupShowOverride: show,
ModalPopupHideOverride: hide
}
}())
};
By the way, it's pretty rare to use new Array() these days. This is usually preferred:
var modalPopupStack = [];
It's shorter, cleaner, and really more explicit.

Related

What type of pattern does this JS adhere to?

I came across code similar to this recently,
// Simplified example..
var Application =
{
MemberVar1: null,
MemberVar2: null,
Initialize: function ()
{
Application.MemberVar1 = 'Foo';
Application.MemberVar2 = 'Bar';
console.log("Initializing..");
Application.GetMemberVars();
},
GetMemberVars: function ()
{
console.log(Application.MemberVar1 + ' ' + Application.MemberVar2);
}
};
$(Application.Initialize);
What is the name of this pattern/method/style? Utilizing OOP principles without using a style I've seen before, such as prototyping. What are the benefits of this style as opposed to other popular ones?
It's a simple one-off object literal that's being created... they can contain functions... perhaps that's what threw you.
The last line merely passes the Application.Initialize function to jQuery as a $(document).ready callback function
In light of the comments below, this is what the code actually does (and how you can write it a lot shorter/easier)
$(function()
{
console.log("Initializing..");
console.log("Foo Bar");//replace this with variables you declare #top of anon. function if you want
});
As a module (you can find out more about the module pattern here):
var Application = (function()
{
var memberVar1, memberVar2,
getMemberVars = function()
{
return memberVar1 + ' ' + memberVar2;
};
return {init: function()
{
memberVar1 = 'Foo';
memberVar2 = 'Bar';
console.log('initializing...');
console.log(getMemberVars());
}};
}());
$(Application.init);
Application is now an object literal, with only 1 property (init): a function that, because it was declared within the scope of that IIFE, has access to all variables local to that scope. That's the magic of closures for you. You can easily add getters and setters for the member vars, too:
var Application = (function()
{
var memberVars = {},//turned into object literal...
getMemberVars = function(all)
{
var i;
if(typeof all === 'string' || typeof all === 'number')
{
return memberVars[all];
}
all = [];
for (i in memberVars)
{
if (memberVars.hasOwnProperty(i))
{
all.push(memberVars[i]);
}
}
return all;//or all.join(' '), as you please
},
get = function(name)
{
return typeof name === 'undefined' ? name : memberVars[name];
},
set = function(name, val)
{
memberVars[name] = val;
};
return {init: function()
{
memberVars.one = 'Foo';
memberVars.two = 'Bar';
console.log('initializing...');
console.log(getMemberVars().join(' '));
},
get: get,
set: set};//just add getter and setter here
}());
This has the same behavior as your code:
var Application = (function() {
var app = {
MemberVar1: null,
MemberVar2: null,
GetMemberVars: function() { /* ... */},
Initialize: function() {
this.MemberVar1 = 'Foo';
this.MemberVar2 = 'Bar';
console.log('Initializing..');
this.getMemberVars();
}
};
$(function() {app.Initialize();});
return app;
}());
But there's a good chance that you don't really want that Initialize function hanging around. So this would simplify it:
var Application = (function() {
var app = {
MemberVar1: null,
MemberVar2: null,
GetMemberVars: function() { /* ... */}
};
$(function() {
app.MemberVar1 = 'Foo';
app.MemberVar2 = 'Bar';
console.log('Initializing..');
app.getMemberVars();
});
return app;
}());
And unless you're actually worried about code trying to access Application.MemberVar1, etc before jQuery's document.ready event, you can simplify it further to this:
var Application = (function() {
var app = {
GetMemberVars: function() { /* ... */}
};
$(function() {
app.MemberVar1 = 'Foo';
app.MemberVar2 = 'Bar';
console.log('Initializing..');
app.getMemberVars();
});
return app;
}());
I'm assuming that defining those MemberVars took some real work, and were not simple strings as in the example. If that's not the case, then I would switch this last to
var Application = (function() {
var app = {
MemberVar1: 'Foo';
MemberVar2: 'Bar';
GetMemberVars: function() { /* ... */}
};
$(function() {
console.log('Initializing..');
app.getMemberVars();
});
return app;
}());
You don't need to use prototype if you are going to use only one instance of some object.
In this case it's pretty clear the Application object is something unique and the author didn't intend there were going to be any additional copies of Application created.
Talking about style... that capital camel case looks ugly. The common agreement is to use CapitalCamelCase only for object constructors. I personally think it's ok to use for unique objects with logic too (Application). But using it for function names and variables should be avoided.
Talking about patterns... it's close to Singleton pattern. But don't think too much about it. All those OOP patterns from Java world lose part of their appeal in JS world. Some of them disintegrate completely. Concentrate on JS ways of solving problems.

Javascript executing function with a string

I'm creating a prototype class like so, but I want to call a function using a string as the function name. I found the windowname; example somewhere, but it's not working in my case.
function someObj() {
this.someMethod = function() {
alert('boo');
name = "someOtherMethod";
window[name]();
}
var someOtherMethod = function() {
alert('indirect reference');
}
}
This is because "someOtherMethod" is not a member of the window object as it defined inside the someObj function.
window is only for global variables.
You can't access local variables via a string, unles you use eval, which is almost always a bad idea.
One alternate way is to use an object. This allows you to look up properties using a string.
function someObj() {
var methods = {};
methods.someMethod = function() {
alert('boo');
var name = "someOtherMethod";
methods[name]();
}
methods.someOtherMethod = function() {
alert('indirect reference');
}
}
someOtherMethod is hidden from window and exists only in the scope of your prototype.
Try to move it out.
function someObj() {
this.someMethod = function() {
alert('boo');
name = "someOtherMethod";
window[name]();
}
}
var someOtherMethod = function() {
alert('indirect reference');
}
Although it is a bad idea using globals.
Create your own hash of methods:
function someObj() {
this.someMethod = function() {
alert('boo');
name = "someOtherMethod";
methods[name]();
}
var methods = {
someOtherMethod : function() {
alert('indirect reference');
}
};
}
Your variable is local to your function so it won't be in window. Even if you are working in the global scope, it is better to use your own object than it is to rely on window so you can avoid name collisions.

Invoke javascript function from string

I have the following code in my javascript module, however this requires me to make the functions visible to the outside world.
var mymodule = function() {
var self = null,
init = function () {
self = this;
$('.actionButton').click(function () {
var worklistId = $(this).data('worklistid'),
action = $(this).data('action');
self[action] && self[action](worklistId); //watchout methods marked as not used are used by this invocation
})
},
send = function () {
// some logic
},
finish = function () {
// some logic
},
delete = function () {
// some logic
};
return {
init: init,
send: send,
finish: finish,
delete: delete
};
}();
mymodule.init();
So the only thing I want to return in my module is the init function. However when I do this I cant invoke the functions, because the object (self) only contains the init function visible on the outside.
return {
init: init
};
Is there any solution to invoke my functions like this without making them visible to the outside world? Please no if else statements, because my workflow is bigger then the 3 actions in this example. I want to make my module as closed as possible because this reduces the dependencies.
Update
Here is a updated jsfiddle with one of the proposed solutions, however this is giving me another issue. http://jsfiddle.net/marcofranssen/bU2Ke/
Something like this would work:
var mymodule = function() {
var self = this;
init = function () {
$('.actionButton').click(function () {
var worklistId = $(this).data('worklistid'), action = $(this).data('action');
self[action] && self[action](worklistId); //watchout methods marked as not used are used by this invocation
})
}
self.send = function () {
console.log('send');
}
self.finish = function () {
console.log('finish');
}
self.delete = function (item) {
console.log('delete');
};
return {
init: init,
};
}();
mymodule.init();​
Here's the fiddle:
http://jsfiddle.net/yngvebn/SRqN3/
By setting the self-variable to this, outside the init-function, and attaching the send, finish and delete functions to self, you can use the self[action] syntax from within the init-function
Yes, there is an easy (but perhaps slightly messy) way you can do this without making the functions visible to the global object:
var privateFunctions = { deleter: deleter, send: send};
Then, instead of self[action]();, just do privateFunctions[action](); and you're good to go.
Note that I changed delete to deleter, because delete is a reserved keyword...
var mymodule = function() {
var self = {},
init = function () {
$('.actionButton').click(function () {
var worklistId = $(this).data('worklistid'),
action = $(this).data('action');
self[action] && self[action](worklistId); //watchout methods marked as not used are used by this invocation
})
};
self.send = function () {
// some logic
};
self.finish = function () {
// some logic
};
self.delete = function () {
// some logic
};
return{
init:init
}
}();
mymodule.init();
This should Work!!
Even if you return an object just with the init property and you populate the rest dynamically such that your module uses them, you would still be making them visible to the outside at runtime. Anyone who wants to debug your module would easily get to them.
You can still create anonymous methods at runtime and they would also be visible together with their implementation.
In your code example, it is vague what "self" really is. You should keep it simple, use encapsulated functions as "private" methods and return a "public" (or "privileged" as Crockford calls it) function that have access to them.
This is the YUI way of doing singletons with private functions and variables. Example pattern:
var mymodule = (function() {
var internal = {
'send': function() {},
'finish': function() {},
'delete': function() {}
};
return {
'init': function(action) {
// access to internals, f.ex:
if ( internal.hasOwnProperty(action) ) {
internal[action].call(this); // bring the caller context
}
}
};
}());
mymodule.init('send');

Basic javascript code layout

I have what I think is a fairly simply question but it's one that I can not find the answer to. I have a objects literal that I have created that groups functions, I want to know how I can create a variable that is inside the objects literal and editable/accessable by all the functions within that objects literal. At the moment the only way I know how to do this is create a global variable but I want to stop populating the global in this way. To better describe what I'm looking fiddle
http://jsfiddle.net/aT3J6/
Thanks, for any help.
var clickCount = 0;
/* I would like to place clickCount inside hideShowFn Object but all function inside need access to it, so global within hideShowFn */
hideShowFn = {
init:function(){
$('.clickMe').click(this.addToCount);
},
addToCount:function(){
clickCount++;
$('<p>'+ clickCount + '</p>').appendTo('body');
}
}
hideShowFn.init();
Create a function which is invoked immediately and returns the object, with the private variable inside the function, like this:
var obj = (function () {
var privateStuff = 'private';
return {
func1: function () {
//do stuff with private variable
},
func2: function () {
//do stuff with private variable
}
};
}());
http://jsfiddle.net/BE3WZ/
This is the way to have private variables in Functional Programming.
http://jsfiddle.net/mattblancarte/aT3J6/10/
Another option would be the pseudo-classical style:
function Constructor(){
var private = 'private';
this.public = 'public';
this.methods = {
//your methods here...
};
}
var obj = new Constructor();
Don't forget to use the 'new' keyword, or else you are going to be globally scoped.
Your code translated to this style would be:
function Test(){
var that = this,
clickCount = 0;
this.init = function(){
$('.clickMe').click(this.addToCount);
};
this.addToCount = function(){
clickCount++;
$('<p>'+ clickCount + '</p>').appendTo('body');
};
}
var test = new Test();
test.init();
You can make a closure as Cokegod says or you can simply add the variable to the object and access it using this
hideShowFn = {
clickCount: 0,
init:function(){
$('.clickMe').click(this.addToCount);
},
addToCount:function(){
this.clickCount++;
$('<p>'+ this.clickCount + '</p>').appendTo('body');
}
}
hideShowFn.init();
This dosn't work as Musa says the scope in addToCount will be the dom node clicked.
But see Cokegod's answer.

JavaScript Namespace

I want to create a global namespace for my application and in that namespace I want other namespaces:
E.g.
Dashboard.Ajax.Post()
Dashboard.RetrieveContent.RefreshSalespersonPerformanceContent();
I also want to place them in seperate files:
Ajax.js
RetrieveContent.js
However I have tried using this method, however it won't work because the same variable name is being used for the namespace in 2 seperate places. Can anyone offer an alternative?
Thanks.
You just need to make sure that you don't stomp on your namespace object if it's already been created. Something like this would work:
(function() {
// private vars can go in here
Dashboard = Dashboard || {};
Dashboard.Ajax = {
Post: function() {
...
}
};
})();
And the RetrieveContent file would be defined similarly.
Here is a very good article on various "Module Patterns" in JavaScript. There is a very nice little section on how you can augment modules, or namespaces and maintain a cross-file private state. That is to say, the code in separate files will be executed sequentially and properly augment the namespace after it is executed.
I have not explored this technique thoroughly so no promises... but here is the basic idea.
dashboard.js
(function(window){
var dashboard = (function () {
var my = {},
privateVariable = 1;
function privateMethod() {
// ...
}
my.moduleProperty = 1;
my.moduleMethod = function () {
// ...
};
return my;
}());
window.Dashboard = dashboard;
})(window);
dashboard.ajax.js
var dashboard = (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
my.ajax = function(){
// ...
}
return my;
}(dashboard || {}));
dashboard.retrieveContent.js
var dashboard = (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
my.retrieveContent = function(){
// ...
}
return my;
}(dashboard || {}));
The Yahoo Namespace function is exactly designed for this problem.
Added:
The source of the function is available. You can copy it into your own code if you want, change the root from YAHOO to something else, etc.
There are several libraries that already offer this sort of functionality if you want to use or examine a pre-baked (that is, a tested) solution.
YUI.attribute and YUI.base
dojo.mixin
underscore.extend
jQuery.extend
goog.provide and goog.object.extend
The simplest and most bug free one to get going with is probably jQuery.extend, with the deep argument set to true. (The reason I say it is bug free is not because I think that jQuery.extend suffers from less bugs than any of the other libraries -- but because it offers a clear option to deep copy attributes from the sender to the receiver -- which most of the other libraries explicitly do not provide. This will prevent many hard-to-diagnose bugs from cropping up in your program later because you used a shallow-copy extend and now have functions executing in contexts you weren't expecting them to be executing in. (If however you are cognizant of how you will be extending your base library while designing your methods, this should not be a problem.)
With the NS object created, you should just be able to add to it from where ever. Although you may want to try var NS = NS || {}; to ensure the NS object exists and isn't overwritten.
// NS is a global variable for a namespace for the app's code
var NS = NS || {};
NS.Obj = (function() {
// Private vars and methods always available to returned object via closure
var foo; // ...
// Methods in here are public
return {
method: function() {
}
};
}());
You could do something like this...
HTML page using namespaced library:
<html>
<head>
<title>javascript namespacing</title>
<script src="dashboard.js" type="text/javascript"></script>
<script src="ajax.js" type="text/javascript"></script>
<script src="retrieve_content.js" type="text/javascript"></script>
<script type="text/javascript">
alert(Dashboard.Ajax.Post());
alert(Dashboard.RetrieveContent.RefreshSalespersonPerformanceContent());
Dashboard.RetrieveContent.Settings.Timeout = 1500;
alert(Dashboard.RetrieveContent.Settings.Timeout);
</script>
</head>
<body>
whatever...
</body>
</html>
Dashboard.js:
(function(window, undefined){
var dashboard = {};
window.Dashboard = dashboard;
})(window);
Ajax.js:
(function(){
var ajax = {};
ajax.Post = function() { return "Posted!" };
window.Dashboard.Ajax = ajax
})();
Retrieve_Content.js:
(function(){
var retrieveContent = {};
retrieveContent.RefreshSalespersonPerformanceContent = function() {
return "content retrieved"
};
var _contentType;
var _timeout;
retrieveContent.Settings = {
"ContentType": function(contentType) { _contentType = contentType; },
"ContentType": function() { return _contentType; },
"Timeout": function(timeout) { _timeout = timeout; },
"Timeout": function() { return _timeout; }
};
window.Dashboard.RetrieveContent = retrieveContent;
})();
The Dashboard.js acts as the starting point for all namespaces under it. The rest are defined in their respective files. In the Retrieve_Content.js, I added some extra properties in there under Settings to give an idea of how to do that, if needed.
I believe the module pattern might be right up your alley. Here's a good article regarding different module patterns.
http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth
I highly recommend you use this technique:
https://github.com/mckoss/namespace
namespace.lookup('com.mydomain.mymodule').define(function (ns) {
var external = namespace.lookup('com.domain.external-module');
function myFunction() {
...
}
...
ns.extend({
'myFunction': myFunction,
...
});
});
I've been using this pattern for a couple of years; I wish more libraries would do the same thing; it's made it much easier for me to share code across my different projects as well.
i wrote this function to simplify creating namespaces. Mabey it will help you.
function ns(nsstr) {
var t = nsstr.split('.');
var obj = window[t[0]] = window[t[0]] || {};
for (var i = 1; i < t.length; i++) {
obj[t[i]] = obj[t[i]] || {};
obj = obj[t[i]];
}
}
ns('mynamespace.isawesome.andgreat.andstuff');
mynamespace.isawesome.andgreat.andstuff = 3;
console.log(mynamespace.isawesome.andgreat.andstuff);
bob.js can help in defining your namespaces (among others):
bob.ns.setNs('Dashboard.Ajax', {
Post: function () { /*...*/ }
});
bob.ns.setNs('Dashboard.RetrieveContent', {
RefreshSalespersonPerformanceContent: function () { /*...*/ }
});
Implementation:
namespace = function(packageName)
{
// Local variables.
var layers, layer, currentLayer, i;
// Split the given string into an array.
// Each element represents a namespace layer.
layers = packageName.split('.');
// If the top layer does not exist in the global namespace.
if (eval("typeof " + layers[0]) === 'undefined')
{
// Define the top layer in the global namesapce.
eval(layers[0] + " = {};");
}
// Assign the top layer to 'currentLayer'.
eval("currentLayer = " + layers[0] + ";");
for (i = 1; i < layers.length; ++i)
{
// A layer name.
layer = layers[i];
// If the layer does not exist under the current layer.
if (!(layer in currentLayer))
{
// Add the layer under the current layer.
currentLayer[layer] = {};
}
// Down to the next layer.
currentLayer = currentLayer[layer];
}
// Return the hash object that represents the last layer.
return currentLayer;
};
Result:
namespace('Dashboard.Ajax').Post = function() {
......
};
namespace('Dashboard.RetrieveContent').RefreshSalespersonPerformanceContent = function() {
......
};
Gist:
namespace.js

Categories

Resources