In Javascript, How can I have functions for an object that only reside once in memory, while accessing non-static private variables

StackOverflow https://stackoverflow.com/questions/23154475

Question

Consider the following code in java

class x {
   private boolean a;
   public void DoSomethingUsingA() {
       ....... // "a" referenced here
   }
}

x X = new x();
x Y = new x();

Each of X and Y have DoSomethingUsingA(), but the function is only created once in memory.

Now if you try this in javascript

function x() {
    var a;
    this.DoSomethingUsingA= function() {
        ........ // "a" referenced here
    }
}

var X = new x();
var Y = new y();

DoSomethingUsingA() here is defined twice in memory for each object X & Y.

Another attempt would be

var x = (function() {
    var a;
    function constructor() {
      ........
    }

    constructor.prototype.DoSomethingUsingA = function() {
       ....... // "a" referenced here
    }

    return constructor;
}())

var X = new x();
var Y = new y();

now DoSomethingUsingA() is only defined once in memory, but the private variables are static across all derived objects

Question: How can I have the functions for all derived objects be defined only once in memory, while having access to non static private variables for each object.

Was it helpful?

Solution 3

One way to make your values referenceable without exposing to each of them directly on your instance is like this

function Foo(b) {
    var env = {}; // Object to hold variables
    this._getEnvironment = function () { // might want to make this non-enumerable
        return env;
    };
    env.bar = b; // example
}
Foo.prototype.getBar = function () { // inherited, shared
    var env = this._getEnvironment();
    return env['bar'];
};

var x = new Foo(1),
    y = new Foo(2);
x.getBar(); // 1
y.getBar(); // 2
// but remember
x._getEnvironment()['bar']; // 1, still reachable

Now yes you have a different _getEnvironment function for each instance, but all of the other functions are now shared

I used an Object env because this is a safe way to look up a value and property look ups are done with a hash table so extremely fast

JavaScript is never really secure, so whilst you can use closures to make it more difficult to access, don't believe that someone motivated wouldn't be able to get around any security measure you try to implement

OTHER TIPS

Consider not trying to hide your private variables so much.

Despite the fact that in languages like Python or JavaScript you can make some properties invisible for class users using some clever tricks, there are no natural ways or appropriate tools for this in these languages. So if you try to make this sort of constructs, you will end with cumbersome solutions like "static" env object or multiple copies of the same function or something like that.

Quote from the very nice answer to analogous question, fully applicable to JavaScript:

It's cultural. In Python, you don't write to other classes' instance or class variables. In Java, nothing prevents you from doing the same if you really want to - after all, you can always edit the source of the class itself to achieve the same effect. Python drops that pretense of security and encourages programmers to be responsible. In practice, this works very nicely.

If instead you decide not to enforce such privacy, there is a couple of tools and conventions that make your "private" vars easy to use:

  1. Use Object.defineProperty() to control enumerability and configurability of properties.

  2. Use underscores in names to prevent names collision in children. Some libraries have conventions to use other symbols for that. For example, AngularJS use $$ prefixes for private variables.

(And also there is a convention that namesOfParameters start with lower case and ConstructorFunctions - with upper case.)

So your code will look like this:

function X() {
    // constructor
}

Object.defineProperty(X.prototype, "__a", {
    "writable": true,
    "value":    null
    // "configurable" and "enumerable" are false by default
});

X.prototype.doSomethingUsingA = function() {
    this.__a = "somevalue";
    // ...
}

How can I have the functions for all derived objects be defined only once in memory, while having access to non static private variables for each object.

You cannot. A "private" variable, i.e. a local variable from a scope dedicated to an instance, can only be accessed by closure, i.e. a privileged function which needs to be created in the same scope.

Notice that there is nothing wrong with it, functions are cheaper than you seem to think.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top