0

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.

man
  • 197
  • 9
  • 1
    _JavaScript_ doesn't have a "private" and "public", to access something like this, you'll need to make it referenceable – Paul S. Apr 18 '14 at 12:50

3 Answers3

1

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";
    // ...
}
Community
  • 1
  • 1
Thaumant
  • 2,113
  • 2
  • 19
  • 14
0

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.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
-1

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

Paul S.
  • 64,864
  • 9
  • 122
  • 138
  • _Environment_ may have been a bad name choice, you might want to consider calling it e.g. _getInstanceVariable_ – Paul S. Apr 18 '14 at 13:12
  • Seems that I had some ambiguity in the question (by using get..() as example). I have fixed it now. Its not about referencing and returning private variables, its about using them within functions. Also "getEnvironmentVariable" would be created twice in memory – man Apr 18 '14 at 13:24
  • @man I stated each instance would get a new `gEnv`, the difference is that all of the other functions can go via the `gEnv` so don't need to have new instances themselves – Paul S. Apr 18 '14 at 13:26
  • 1
    @man The problem you're trying to solve assumes there is such a thing as "private" and "public", in _JavaScript_ these concepts simply don't exist. You can use scope and closure to create something _similar_, but it won't be the same as a language which does have the feature. Perhaps you should consider _why_ you want something to be private and _does it really matter_ if it's not? **edit** [**here**](http://javascript.crockford.com/private.html) is Crockford's take on the subject – Paul S. Apr 18 '14 at 13:34
  • Yes you are right, this is the closest solution I've seen so far. Good trade off, The down part is I have to reference everything thought the "gEnv" interface. Maybe should return the "env" object as a whole through the "getEnvironmentVariable". – man Apr 18 '14 at 13:42
  • 1
    Please just make it a public property, maybe underscore-prefixed. Your `getEnvironmentVariable` is insecure, pretending false safety. Also you'd need something similar as a getter - overcomplicating everything. – Bergi Apr 18 '14 at 13:43
  • @Bergi I agree that the restriction I put on it may have been giving a false sense of security so I've removed the prototype checking, simplified it down and changed the related paragraph to re-enforce that _JavaScript_ is never "secure". Thanks for your comment – Paul S. Apr 18 '14 at 15:45