Is there a way to create private global variables in JavaScript? I have tried looking around, and I keep bumping into talk of constructors - which don't seem too global.
Thanks
Not sure what your use case is. I'll assume you have a js script file containing some functions and variables and you want to expose some of those globally, but keep the rest private to your script file. You can achieve this with a closure. Basically you create a function that you execute immediately. Inside the function you place your original code. You then export the functions you need into the global scope.
// Define a function, evaluate it inside of parenthesis
// and execute immediately.
(function(export) {
var myPrivateVariable = 10;
function myPrivateFunction(param) {
return param + myPrivateVariable;
}
export.myGlobalFunction = function(someNumber) {
return myPrivateFunction(someNumber);
};
})(this); // The *this* keyword points to *window* which
// is *the* global scope (global object) in a web browser
// Here it is a parameter - the *export* variable inside the function.
// This is executed in the global scope
myGlobalFunction(2); // yields 12 (i.e. 2 + 10)
myPrivateVariable; // Error, doesn't exist in the global scope
myPrivateFunction(2) // Error, doesn't exist in the global scope
To answer your question, no, that is not possible as there are no access modifiers in javascript. A variable declared in global scope is accessible to any function.
As pointed out in the comments to this answer, you can create objects which have private members. Crockford has a page on private members in Javascript. He uses the following code to illustrate his point:
function Container(param) {
// private method
function dec() {
if (secret > 0) {
secret -= 1;
return true;
} else {
return false;
}
}
this.member = param;
var secret = 3;
var that = this;
// privileged method
this.service = function () {
return dec() ? that.member : null;
};
}
In the above example, param, secret, and that are all private in that they are not accessible from the outside. To be more clear, these variables can only be accessed by privileged or private methods, the difference being that privileged methods can be called from any instance of the object. As is suggested in the comments, this is achievable by using closures.
Quoting from Crockford for a quick explanation on closures, but you can find plenty of related questions.
What this means is that an inner function always has access to the
vars and parameters of its outer function, even after the outer
function has returned.
in order to have private members. you need to use closures.
following code help you understanding the concept.
function CustomArray () {
this.array = [];
var privateData = 'default data';
this.getPrivateData = function () {
return privateData;
};
this.setPrivateData = function (data) {
privateData = data;
};
};
CustomArray.prototype.push = function (data) {
this.array.push(data);
};
CustomArray.prototype.unshift = function (data) {
this.array.unshift(data);
};
CustomArray.prototype.pop = function () {
this.array.pop();
};
CustomArray.prototype.shift = function () {
this.array.shift();
};
CustomArray.prototype.print = function () {
console.log(this.array.join(','));
};
var array = new CustomArray();
array.push(10);
array.push(20);
array.push(30);
array.push(5);
array.unshift(3);
array.unshift(2);
array.unshift(1);
array.unshift(0);
array.pop();
array.shift();
array.print();
console.log(array.getPrivateData());// default data
array.setPrivateData('am new private data');
console.log(array.getPrivateData());//am new private data
Related
I am not clear about the concept of private, if I can still access it through the public method and redefine the properties of the module. I mean, I can perfectly do:
var aModule = (function() {
var privateVar = 1;
return {
publicFunction: function() {
return privateVar;
}
}
})();
aModule.publicFunction = function() {
privateVar = function() {
console.log('a new content');
}
privateVar();
};
aModule.publicFunction(); // 'a new content'
I understand that this is not possible if I write it in ES6 with let or const, because it would give me error try to overwrite the value of the private variable, but what sense does it have in ES5?
A private variable cannot be accessed or changed by code that's outside the module or class that owns the private variable.
For example, you can't do aModule.privateVar and expect it to give you anything back.
What your publicFunction is is what the Java (and other programming languages) world would call a "getter". Simply put it gives access to the value of the private variable, without allowing write access to it.
In your last example, you're not actually overwriting the private variable. You're just creating a new variable within publicFunction's scope and assigning a value to that. Just because it's also named privateVar doesn't mean it's the same area of memory.
I've added to your code to demonstrate this
var aModule = (function() {
var privateVar = 1;
return {
publicFunction: function() {
return privateVar;
},
getPrivateVar() {
return privateVar;
}
}
})();
aModule.publicFunction = function() {
privateVar = function() {
console.log('a new content');
}
privateVar();
};
aModule.publicFunction(); // 'a new content'
console.log(aModule.getPrivateVar()); //outputs 1
To give more detail on why this is, it's all about scope. privateVar exists in an anonymous function's scope. This anonymous function returns an object with several functions defined on it. When the function is called, this object is assigned to aModule, but retains access to privateVar because they share scope.
However, outside of that function we're at a different scope, which doesn't have access to the aModule's variables, except those exposed in the returned object
You are overwriting the public function and not able to access the module private variable
Consider the following new function that is created as a property of aModule that attempts to only change the value of var privateVar
The scope is different because of where it gets called and it isn't able to access that private variable
var aModule = (function() {
var privateVar = 1;
return {
publicFunction: function() {
return privateVar;
}
}
})();
aModule.newFunction = function() {
// try to change privateVar in aModule
privateVar = 3
};
aModule.newFunction();
console.log(aModule.publicFunction()); //still 1 not 3
// here's where it actually ended up
console.log(window.privateVar)
I have this singleton. The public functions allow to set private variables but I am not able to set them in the way that I am able to use them in the private methods:
var ServiceInterface = (function () {
// Instance stores a reference to the Singleton
var instance;
function init() {
// Singleton
// Private methods and variables
var m_action;
function performAction() {
alert(m_action);
}
return {
// Public methods and variables
callBackend: function (sAction) {
m_action = sAction;
}
};
};
})
m_action is not available throughout the public and private section of the singleton. What am I doing wrong?
I think you're referring to this
var ServiceInterface = (function () {
var m_action;
function performAction() {
alert(m_action);
}
return {
// Public methods and variables
callBackend: function (sAction) {
m_action = sAction;
performAction();
}
};
})()
ServiceInterface.callBackend("Hello world");
You need to execute anonymous function. Running it enables to create variables and functions defined with the anonymous function and these cannot be seen outside. Most of js libraries use this convention to create modules and to avoid infecting the global scope
var ServiceInterface = (function () {
// code inside
})()
These are the variables and functions confined within the scope of anonymous function executed
// var ServiceInterface = (function () {
var m_action;
function performAction() {
alert(m_action);
}
// })()
Finally, return a javascript object that will expose functions that can be accessible outside the anonymous function scope
//var ServiceInterface = (function () {
// var m_action;
//
// function performAction() {
// alert(m_action);
// }
return {
// Public methods and variables
callBackend: function (sAction) {
m_action = sAction;
performAction();
}
};
//})()
However, why go through the trouble of making private variable and method for a singleton?
This is how you create a singleton with a private member variable.
ServiceInterface = new (function() {
var m_action = false;
this.setAction = function(s) {
m_action = s;
};
this.getAction = function() {
return m_action;
};
this.performAction = function() {
alert(ServiceInterface.getAction());
};
this.createCallback = function() {
return function(sAction) {
ServiceInterface.setAction(sAction);
};
}
})();
ServiceInterface.setAction("secret");
ServiceInterface.performAction();
ServiceInterface becomes a singleton because the constructor function is thrown away after it's created. ServiceInterface = new (.....)(); is how it's executed right after being declared. It's a singleton because there is no way for someone to create another instance.
I don't use var to create the instance. When you exclude var and you're not inside a function the new variable will be attached to the prototype of the parent object. In the browser this will be window. window is like a global singleton in javascript.
The local variable m_action is persisted because setAction and getAction reference it as closure functions, and the variable is attached to their scope. So they can be used as setter/getter methods.
You can now use ServiceInterface.setAction(sAction); in your callbacks to set the private member.
http://jsfiddle.net/thinkingmedia/w7DdE/6/
I have JavaScript code as below;
var foo = (function() {
//Private vars
var a = 1;
return {
//Public vars/methods
a: a,
changeVar: function () {
a = 2;
}
}
})();
Now I am not sure how the syntax for public vars/methods works ?
Could you please corelate how just "returning" the vars/methods makes them as public ?
Thank you.
The value of the variable foo is actually the value returned by this function. Notice on the last line, the (), indicating that this function is evaluated immediately. By evaluating a function and assigning its return value to a variable, you are able to hide variables inside a local (function) scope, such that they are not accessible outside that scope. Only members on the returned object are accessible, but because any functions inside form a closure with their outer scope, you can still use local (hidden) variables.
An example of this would be to hide some local state and only allow access to it through a method:
var foo = (function() {
//Private vars
var a = 1;
return {
//Public methods
getVar: function () {
return a;
},
setVar: function (val) {
a = val;
}
}
})();
Okay, you've returned an object in the anonymous function, which means that the object is assigned to foo. So you can access the object's properties like foo.a or foo.changeVar, but you can continue to let the private variables exist, within the function's scope. Can't help much without a more specific question.
I'm trying to assign a callback dynamically to an Object of mine, I can't seem to figure out a way to do this while granting this function access to private variables. I've listed the relavant code below with comments where I ran into walls.
Object Factory
function makeObj ( o ) {
function F() {}
F.prototype = o;
return new F();
}
Module
var MODULE = (function(){
var myMod = {},
privateVar = "I'm private";
return myMod;
})();
Various Attempts
myMod.someDynamicFunc = function someDynamicFunc(){
//privateVar === undefined;
alert( privateVar );
}
myMod.someDynamicFunc();
myMod.prototype.someDynamicFunc = function someDynamicFunc(){
//ERROR: Cannot set property 'someDynamicFunc' of undefined
alert(privateVar);
}
myMod.someDynamicFunc();
In this attempt I tried making a setter in the module object... to no avail.
var MODULE = (function(){
var myMod = {},
privateVar = "I'm private";
myMod.setDynamicFunction = function ( func ){
if(func !== undefined && typeof func === "function"){
//Uncaught TypeError:
// Cannot read property 'dynamicFunction' of undefined
myMod.prototype.dynamicFunction = func;
//also tried myMod.dynamicFunction = func;
}
}
return myMod;
})();
var myModule = makeObject( MODULE );
myModule.setDynamicFunction(function(){
alert(privateVar);
});
myModule.dynamicFunction();
Am I just using JavaScript wrong? I'd really like to be able to assign callbacks after the object is initiated. Is this possible?
You can't access the private variable via a callback function set dynamically (since it can't be a closure if it's attached later), but you can set up a system by which you would be able to access the variable:
var MODULE = (function(){
var myMod = {},
privateVar = "I'm private";
myMod.callback = function(fn) {fn(privateVar);};
return myMod;
})();
var someDynamicFunc = function(param) {alert(param);};
myMod.callback(someDynamicFunc);
Of course, this makes it not really private, since anyone could do this. I don't see how it would be possible at all for you to have a "private" variable that you access via dynamically attached functions, without allowing anyone else's dynamically attached functions to have the same privilege (thus making it not really private).
I guess you did not really understand exactly how closures work.
Closures mean that scopes always have access to the outer scope they were defined in.
function Counter(start) {
var count = start;
return {
increment: function() { // has access to the outer scope
count++;
},
get: function() {
return count;
}
}
}
var foo = new Counter(4);
foo.increment();
foo.get(); // 5
The above example returns two closures, both the function increment as well as get keep a reference to the count variable defined in the constructor.
One cannot access count from the outside, the only way to interact with it is via the two "closured" functions.
Remember, closures work by keeping a reference to their outer scopes, so the following does not work:
var foo = new Counter(4);
foo.hack = function() { // is not getting defined in the same scope that the original count was
count = 1337;
};
This will not change the variable count that's inside of Counter since foo.hack was not defined in that scope, instead, it will create or override the global variable count.
For my web application, I am creating a namespace in JavaScript like so:
var com = {example: {}};
com.example.func1 = function(args) { ... }
com.example.func2 = function(args) { ... }
com.example.func3 = function(args) { ... }
I also want to create "private" (I know this doesn't exist in JS) namespace variables but am not sure what's the best design pattern to use.
Would it be:
com.example._var1 = null;
Or would the design pattern be something else?
Douglas Crockford popularized so called Module Pattern where you can create objects with "private" variables:
myModule = function () {
//"private" variable:
var myPrivateVar = "I can be accessed only from within myModule."
return {
myPublicProperty: "I'm accessible as myModule.myPublicProperty"
}
};
}(); // the parens here cause the anonymous function to execute and return
But as you said Javascript doesn't truly have private variables and I think this is somewhat of a cludge, which break other things. Just try to inherit from that class, for example.
Closures are frequently used like this to simulate private variables:
var com = {
example: (function() {
var that = {};
// This variable will be captured in the closure and
// inaccessible from outside, but will be accessible
// from all closures defined in this one.
var privateVar1;
that.func1 = function(args) { ... };
that.func2 = function(args) { ... } ;
return that;
})()
};
After 7 years this might come quite late, but I think this might be useful for other programmers with a similar problem.
A few days ago I came up with the following function:
{
let id = 0; // declaring with let, so that id is not available from outside of this scope
var getId = function () { // declaring its accessor method as var so it is actually available from outside this scope
id++;
console.log('Returning ID: ', id);
return id;
}
}
This might only be useful if you are in a global scope and want to declare a variable that is not accessible from anywhere except your function that sets the value of id one up and returns its value.