Reputation: 267077
Say I have a javascript function/class called Foo
and it has a property called bar
. I want the value of bar
to be supplied when the class is instantiated, e.g:
var myFoo = new Foo(5);
would set myFoo.bar
to 5.
If I make bar
a public variable, then this works, e.g:
function Foo(bar)
{
this.bar = bar;
}
But if I want to make it private, e.g:
function Foo(bar)
{
var bar;
}
Then how would I set the value of the private variable bar
such that its available to all internal functions of foo
?
Upvotes: 18
Views: 37954
Reputation: 26161
In ES6+ terms the proper way to do this is as shown in the @Nitin Jadhav's answer. However if for some reason you would like to stick with the good old constructor functions it could be achieved like;
function Foo(val){
function Construct(){};
Construct.prototype = { set bar(_){} // you may throw an error here
, get bar(){return val;}
};
return new Construct();
};
So two things happen here.
Foo
with properties like in the accepted answer.Private Class Fields
abstraction you are free to throw an error or not when someone tries to access the private variable through the setter
.Perhaps you would like a private field of the instance itself instead of accessing it through the prototype. Then you may do like;
function Foo(val){
Object.defineProperty(this,"bar",{ set: function(){}
, get: function(){return val;}
});
};
Upvotes: 0
Reputation: 7306
If you are willing to use ES2015 classes,
with ESNext, you can use Javascript private variables like this:
class Foo {
#bar = '';
constructor(val){
this.#bar = val;
}
otherFn(){
console.log(this.#bar);
}
}
Private field #bar is not accessible outside Foo class.
Upvotes: 5
Reputation: 5601
One way I can think of is to use a closure that's assigned to a name and returns a new object. You would pass in any arguments to the constructor through the call to the closure. That would end up being something like the following:
var fooFactory = function (a, b) {
var c = 5,
d = 6,
foo;
foo = function (a, b) {
this.a = a;
this.b = b;
this.bar();
}
foo.prototype.bar = function () {
//do something with c and d
this.c = c + d;
}
foo.prototype.getC = function () {
return c;
}
foo.prototype.getD = function () {
return d;
}
return new foo(a, b);
};
This way, a and b are always declared uniquely. You would then construct your object like so:
var obj = fooFactory(1, 2);
//obj contains new object: { a: 1, b: 2, c: 11 }
console.log(obj.getC());
//returns 5
Upvotes: 4
Reputation: 267
I recently had a similar issue but wanted to use accessor properties also. Below is a Foo(Bar) example based on what I came up with for a solution. This example is trivial but can easily be expanded upon using more complex get/set functions.
function Foo(Bar){
Object.defineProperty(this,"bar",{get:function(){return Bar},set:function(val){Bar=val}});
}
x=new Foo(3);
y=x.bar; //3
x.bar++; //x.bar==4
Upvotes: -2
Reputation: 141829
function Foo(b)
{
var bar = b;
this.setBar = function(x){
bar = x;
}
this.alertBar = function(){
alert(bar);
}
}
var test = new Foo(10);
alert(test.bar); // Alerts undefined
test.alertBar(); // Alerts 10
Upvotes: 4
Reputation: 38264
You have to put all functions that need to access the private variable inside the constructor:
function Foo(bar)
{
//bar is inside a closure now, only these functions can access it
this.setBar = function() {bar = 5;}
this.getBar = function() {return bar;}
//Other functions
}
var myFoo = new Foo(5);
myFoo.bar; //Undefined, cannot access variable closure
myFoo.getBar(); //Works, returns 5
Upvotes: 24
Reputation: 707326
One of the best tutorials on private and protected access in javascript is here: http://javascript.crockford.com/private.html.
function Foo(a) {
var bar = a; // private instance data
this.getBar = function() {return(bar);} // methods with access to private variable
this.setBar = function(a) {bar = a;}
}
var x = new Foo(3);
var y = x.getBar(); // 3
x.setBar(12);
var z = x.bar; // not allowed (x has no public property named "bar")
Upvotes: 56