Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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());
like image 742
Paweł Witkowski Photography Avatar asked Jan 27 '09 12:01

Paweł Witkowski Photography


People also ask

How do you define a private member in JavaScript?

Class fields are public by default, but private class members can be created by using a hash # prefix. The privacy encapsulation of these class features is enforced by JavaScript itself. Private members are not native to the language before this syntax existed.

Is there private in JavaScript?

JavaScript allows you to define private methods for instance methods, static methods, and getter/setters. The following shows the syntax of defining a private instance method: class MyClass { #privateMethod() { //... } }

What is the drawback of creating true private in JavaScript?

There are two major disadvantages of creating the true private method in JavaScript. Cannot call private method outside the class. Create memory inefficiency when different objects are created for the same class, as a new copy of the method would be created for each instance.

What is difference between __ proto __ and prototype?

prototype is a property of a Function object. It is the prototype of objects constructed by that function. __proto__ is an internal property of an object, pointing to its prototype.


2 Answers

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;
})();
like image 133
Christoph Avatar answered Sep 19 '22 05:09

Christoph


With modern browsers adopting some ES6 technologies, you can use WeakMap to get around the GUID problem. This works in IE11 and above:

// Scope private vars inside an IIFE
var Foo = (function() { 
    // Store all the Foos, and garbage-collect them automatically
    var fooMap = new WeakMap();

    var Foo = function(txt) { 
        var privateMethod = function() { 
            console.log(txt); 
        };
        // Store this Foo in the WeakMap
        fooMap.set(this, {privateMethod: privateMethod}); 
    } 

    Foo.prototype = Object.create(Object.prototype); 
    Foo.prototype.public = function() { 
        fooMap.get(this).p(); 
     } 
     return Foo; 
 }());

 var foo1 = new Foo("This is foo1's private method");
 var foo2 = new Foo("This is foo2's private method");
 foo1.public(); // "This is foo1's private method"
 foo2.public(); // "This is foo2's private method"

WeakMap won't store references to any Foo after it gets deleted or falls out of scope, and since it uses objects as keys, you don't need to attach GUIDs to your object.

like image 39
Zacqary Avatar answered Sep 21 '22 05:09

Zacqary