Question

Hi everybody I have read that what I ask is not possible (and I imagine why if considering that private fields are achieved through clousure).

( Eg : previously I have read that post Access "private" variables in prototype )

So I worked to a possible workaround. In my case I would that a private property (called __counter) could be setted only through prototype, because everybody else (except me) who try to access to that "private" field, could potentially break my object's functionality.

function Test(_c) {
    var __counter = _c;

    this.getCounter = function() {
        return __counter;
    };

    this.increment = function() {
        for (var proto in Test.prototype)
            if (Test.prototype[proto] == arguments.callee.caller)
                return ++__counter;

        return undefined;
    };

}

Test.prototype.getNext = function() {
    return this.increment();
};

var t1 = new Test(1);

alert(t1.getCounter());
alert(t1.getNext());
alert(t1.increment());
alert(t1.getCounter());

My question now is if that solution is acceptable, and if it is how to improve some performance issues that I've noticed.

I suppose that looping on object prototype for each call could be expensive (use of hash table instead?) and I know that use of arguments.callee.caller is deprecated (and break the inlining in js compiler).

So excluding that performance issues (that I hope to mitigate), are there practical advantage using that method instead of define all methods in the object constructor? (I know this case is trivial, but for more complex cases where only few properties must be accessed privately and there are a lot of methods that "need" to be defined in the prototype).

Was it helpful?

Solution

No, it's not acceptable, since this code will easily break your "fix":

Test.prototype.myIncrement = function() {
    return this.increment();
};

This is defined in the prototype, and thus it can access this.increment. JavaScript allows prototypes to be modified at runtime, and prototypes edits are shared among all instances of the object.

//Test "class"

var t1 = new Test(1);
Test.prototype.myIncrement = function() {
    return this.increment();
};

console.log(t1.getCounter());
console.log(t1.getNext());
console.log(t1.myIncrement());
console.log(t1.getCounter());

Remember that JavaScript is executed on the client machine, so it can be modified as the owner prefers. You can make it harder to someone to modify your code, but it is never impossible.

Sidenote:

I suppose that looping on object prototype for each call could be expensive (use of hash table instead?) and I know that use of arguments.callee.caller is deprecated (and break the inlining in js compiler).

Yes, it could be extremely expensive, but in this case(since the prototype is small) the true problem is arguments.caller.callee. This is what is causing your performance issues. One last thing, when looping with a for..in operator remember to use hasOwnProperty, or you could have unexpected results.

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