Javascript public variable/methods - javascript

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.

Related

Private Variables in Module Pattern

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)

Way to make global private variables in javascript?

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

Dynamically attach a function to grant access to private variables

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.

When returning an object from a JavaScript constructor function (avoiding 'new') how do I implement public members?

I have begun writing my 'class' type JavaScript functions like the Module Pattern or Revealing Module patten. This avoids the use of 'new' and allows me to define which functions are public in a single place. However, I have been unable to see how to use and access public data members in this pattern.
e.g. the member 'id' below is accessible through myobj.getId(), but myobj.id is undefined.
function setup(){
var myobj = MyObject();
myobj.initialize();
alert(myobj.getId()); // returns 3, as expected
alert(myobj.id); // returns undefined
}
function MyObject(){
var id;
function initialize(){
//do some stuff that initializes data including...
id = 3;
}
return{
initialize:initialize,
id:id,
getId:function(){ return id;}
}
}
Is there no way to get myobj.id to work returning the value that was set in initialize()?
Your problem is that you aren't taking advantage of closure. The line id:id creates a new variable as a member of the object literal you are returning. This has the default value undefined. Then you are assigning the same variable id back to itself, undefined again.
Also, a module is a single object instance, not a factory function. Try something like this:
var myModule = (function(opts) {
var foo = opts.foo || 0, //private variables with default values
bar = opts.bar || 0, // if none are passed in
product = function() { //private method
return (foo * bar);
};
return {
getFoo : function() { //public methods
return foo;
},
fooTimesBar : function() {
return product();
}
}
})({
foo : 5, //options object
bar : 7
});
The core of the module pattern is a self executing anonymous function that declares variables and then returns an object that has privileged access to those variables through closure.
The extra parens at the end, here containing an object literal with some options that get passed in, executes the function, which then returns an object and assigns it to myModule.
Anything declared as a member of that returned object can be accessed publicly. Code in the returned object has access to the variables defined in the anonymous function through closure even after the function has returned. The variables declared in the anonymous function are effectively private. Code outside the function cannot address them except through the methods provided in the returned object.
The whole thing results in a single object instance in myObject. No more than one can be created, which is the definition of a module. A similar approach could be taken the create a factory function however.
The reason is that your variable id is set to undefined by default and it's type will be undefined as well. Now, because undefined type is a primitive one your assignment in the returned object will be a value assignment, not reference. So obj.id will become undefined in the instance and not the same as the id variable in the constructor function.
Now initialize will change the id in the constructor function, and getId will return the same id, but obj.id will refer to the undefined object property.
function MyObject(){
// initialize is used as a public function so
// this will always refer to the current instance
function initialize(){
this.id = 3;
}
return {
// no need to define id here it will
// report undefined on access by default
initialize: initialize,
getId:function(){ return this.id; }
}
}
Run the whole stuff to see it works as expected.
​
You can solve this and still maintain the syntactic sugar of the Revealing module pattern by returning a cached object instead of an anonymous one.
eg:
NAMESPACE.Module = (function () {
//All public members go on api
var api = {}
api.id = 3;
//Private members
var self,
foo,
bar;
/**
#public
*/
api.init = function () {
self = this;
console.log(this); //NAMESPACE.Module
}
/**
#private
*/
function _privateFunction() {
console.log(self); //NAMESPACE.Module
}
return api;
}());

Setting javascript prototype function within object class declaration

Normally, I've seen prototype functions declared outside the class definition, like this:
function Container(param) {
this.member = param;
}
Container.prototype.stamp = function (string) {
return this.member + string;
}
var container1 = new Container('A');
alert(container1.member);
alert(container1.stamp('X'));
This code produces two alerts with the values "A" and "AX".
I'd like to define the prototype function INSIDE of the class definition. Is there anything wrong with doing something like this?
function Container(param) {
this.member = param;
if (!Container.prototype.stamp) {
Container.prototype.stamp = function() {
return this.member + string;
}
}
}
I was trying this so that I could access a private variable in the class. But I've discovered that if my prototype function references a private var, the value of the private var is always the value that was used when the prototype function was INITIALLY created, not the value in the object instance:
Container = function(param) {
this.member = param;
var privateVar = param;
if (!Container.prototype.stamp) {
Container.prototype.stamp = function(string) {
return privateVar + this.member + string;
}
}
}
var container1 = new Container('A');
var container2 = new Container('B');
alert(container1.stamp('X'));
alert(container2.stamp('X'));
This code produces two alerts with the values "AAX" and "ABX". I was hoping the output would be "AAX" and "BBX". I'm curious why this doesn't work, and if there is some other pattern that I could use instead.
EDIT: Note that I fully understand that for this simple example it would be best to just use a closure like this.stamp = function() {} and not use prototype at all. That's how I would do it too. But I was experimenting with using prototype to learn more about it and would like to know a few things:
When does it make sense to use prototype functions instead of closures? I've only needed to use them to extend existing objects, like Date. I've read that closures are faster.
If I need to use a prototype function for some reason, is it "OK" to define it INSIDE the class, like in my example, or should it be defined outside?
I'd like to understand why the privateVar value of each instance is not accessible to the prototype function, only the first instance's value.
When does it make sense to use prototype functions instead of closures?
Well, it's the most lightweight way to go, let's say you have a method in the prototype of certain constructor, and you create 1000 object instances, all those objects will have your method in their prototype chain, and all of them will refer to only one function object.
If you initialize that method inside the constructor, e.g. (this.method = function () {};), all of your 1000 object instances will have a function object as own property.
If I need to use a prototype function for some reason, is it "OK" to define it INSIDE the class, like in my example, or should it be defined outside?
Defining the members of a constructor's prototype inside itself, doesn't makes much sense, I'll explain you more about it and why your code doesn't works.
I'd like to understand why the privateVar value of each instance is not accessible to the prototype function, only the first instance's value.
Let's see your code:
var Container = function(param) {
this.member = param;
var privateVar = param;
if (!Container.prototype.stamp) { // <-- executed on the first call only
Container.prototype.stamp = function(string) {
return privateVar + this.member + string;
}
}
}
The key point about your code behavior is that the Container.prototype.stamp function is created on the first method invocation.
At the moment you create a function object, it stores the current enclosing scope in an internal property called [[Scope]].
This scope is later augmented when you call the function, by the identifiers (variables) declared within it using var or a FunctionDeclaration.
A list of [[Scope]] properties forms the scope chain, and when you access an identifier (like your privateVar variable), those objects are examined.
And since your function was created on the first method invocation (new Container('A')), privateVar is bound to the Scope of this first function call, and it will remain bound to it no matter how do you call the method.
Give a look to this answer, the first part is about the with statement, but in the second part I talk about how the scope chain works for functions.
Sorry for resurrecting an old question, but I wanted to add something that I recently discovered somewhere else here on SO (looking for the link, will edit/add it once I find it): found it.
I personally like the below methodology because I can visually group all my prototype and 'instance' definitions together with the function definition, while avoiding evaluating them more than once. It also provides an opportunity to do closures with your prototype methods, which can be useful for creating 'private' variables shared by different prototype methods.
var MyObject = (function () {
// Note that this variable can be closured with the 'instance' and prototype methods below
var outerScope = function(){};
// This function will ultimately be the "constructor" for your object
function MyObject() {
var privateVariable = 1; // both of these private vars are really closures specific to each instance
var privateFunction = function(){};
this.PublicProtectedFunction = function(){ };
}
// "Static" like properties/functions, not specific to each instance but not a prototype either
MyObject.Count = 0;
// Prototype declarations
MyObject.prototype.someFunction = function () { };
MyObject.prototype.someValue = 1;
return MyObject;
})();
// note we do automatic evalution of this function, which means the 'instance' and prototype definitions
// will only be evaluated/defined once. Now, everytime we do the following, we get a new instance
// as defined by the 'function MyObject' definition inside
var test = new MyObject();
You need to put the function on each specific instance instead of the prototype, like this:
Container = function(param) {
this.member = param;
var privateVar = param;
this.stamp = function(string) {
return privateVar + this.member + string;
}
}
To get the behavior you want you need to assign each individual object separate stamp() functions with unique closures:
Container = function(param) {
this.member = param;
var privateVar = param;
this.stamp = function(string) {
return privateVar + this.member + string;
}
}
When you create a single function on the prototype each object uses the same function, with the function closing over the very first Container's privateVar.
By assigning this.stamp = ... each time the constructor is called each object will get its own stamp() function. This is necessary since each stamp() needs to close over a different privateVar variable.
That is because privateVar is not a private member of the object, but part of stamp's closure. You could get the effect by always creating the function:
Container = function(param) {
this.member = param;
var privateVar = param;
this.stamp = function(string) {
return privateVar + this.member + string;
}
}
The value of privateVar is set when the function is built, so you need to create it each time.
EDIT: modified not to set the prototype.

Categories