Search code examples
javascriptprototypeprivate

Javascript private member on prototype


Well I tried to figure out is this possible in any way. Here is code:

a=function(text)
{
   var b=text;
   if (!arguments.callee.prototype.get)
      arguments.callee.prototype.get=function()
    {
         return b;
    }
    else
      alert('already created!');
}

var c=new a("test");  // creates prototype instance of getter
var d=new a("ojoj");  // alerts already created
alert(c.get())        // alerts test 
alert(d.get())        // alerts test from context of creating prototype function :(

As you see I tried to create prototype getter. For what? Well if you write something like this:

a=function(text)
{
    var b=text;
    this.getText=function(){ return b}
}

... everything should be fine.. but in fact every time I create object - i create getText function that uses memory. I would like to have one prototypical function lying in memory that would do the same... Any ideas?

EDIT:

I tried solution given by Christoph, and it seems that its only known solution for now. It need to remember id information to retrieve value from context, but whole idea is nice for me :) Id is only one thing to remember, everything else can be stored once in memory. In fact you could store a lot of private members this way, and use anytime only one id. Actually this is satisfying me :) (unless someone got better idea).

someFunc = function()
{
  var store = new Array();
  var guid=0;
  var someFunc = function(text)
  {
    this.__guid=guid;
    store[guid++]=text;
  }

  someFunc.prototype.getValue=function()
  {
    return store[this.__guid];
  }

  return someFunc;
}()

a=new someFunc("test");
b=new someFunc("test2");

alert(a.getValue());
alert(b.getValue());

Solution

  • JavaScript traditionally did not provide a mechanism for property hiding ('private members').

    As JavaScript is lexically scoped, you could always simulate this on a per-object level by using the constructor function as a closure over your 'private members' and defining your methods in the constructor, but this won't work for methods defined in the constructor's prototype property.

    Of course, there are ways to work around this, but I wouldn't recommend it:

    Foo = (function() {
        var store = {}, guid = 0;
    
        function Foo() {
            this.__guid = ++guid;
            store[guid] = { bar : 'baz' };
        }
    
        Foo.prototype.getBar = function() {
            var privates = store[this.__guid];
            return privates.bar;
        };
    
        Foo.prototype.destroy = function() {
            delete store[this.__guid];
        };
    
        return Foo;
    })();
    

    This will store the 'private' properties in another object seperate from your Foo instance. Make sure to call destroy() after you're done wih the object: otherwise, you've just created a memory leak.


    edit 2015-12-01: ECMAScript6 makes improved variants that do not require manual object destruction possible, eg by using a WeakMap or preferably a Symbol, avoiding the need for an external store altogether:

    var Foo = (function() {
        var bar = Symbol('bar');
    
        function Foo() {
            this[bar] = 'baz';
        }
    
        Foo.prototype.getBar = function() {
            return this[bar];
        };
    
        return Foo;
    })();