I'm following Crockford's guide to private methods in Javascript, and I'm struggling with something. I'm trying to optimize this code
function Container(param) {
function dec() {
if (secret > 0) {
secret -= 1;
return true;
} else {
return false;
}
}
this.member = param;
var secret = 3;
var that = this;
this.service = function () {
return dec() ? that.member : null;
};
}
by defining the functions outside of the constructor so that a new function object isn't created each time a new instance is created.
I still have no idea of how to do this for those he refers to as private methods (any help is well appreciated). For those he calls privileged methods this is what I'm trying to do:
function Container(param) {
function dec() {
if (secret > 0) {
secret -= 1;
return true;
} else {
return false;
}
}
this.member = param;
var secret = 3;
var that = this;
}
Container.prototype.service = function() {
return dec() ? that.member : null;
};
but if I test it like this
d1 = new Container("content");
d1.service();
I get this error:
ReferenceError: dec is not defined
Does this mean there's no way of using the advantages of the private/privileged methods Crockford uses AND optimizing memory usage by linking all instances of the class to the same function object? I hope you'll prove me wrong.
If you don't want to create a new dec
on every call of Container
, you can make Container
into an IIFE - define dec
when Container
is defined, and then return the actual Container
constructor from the IIFE, so that dec
is only referenceable from inside the Container
. To encapsulate the secrets
, use a Map
indexed by instance instead of using a plain var secrets
in the constructor, so that the (shared) dec
and service
functions can see and use the Map.
Actually, as comment notes, it'd probably be better to use a WeakMap so that an instance's associated secret can be garbage collected once the instance is GC'd:
const Container = (() => {
const secretsByInstance = new WeakMap();
function dec(instance) {
const secret = secretsByInstance.get(instance);
if (secret > 0) {
secretsByInstance.set(instance, secret - 1);
return true;
} else {
return false;
}
}
function Container(param) {
secretsByInstance.set(this, 3);
this.member = param;
}
Container.prototype.service = function() {
return dec(this) ? this.member : null;
};
return Container;
})();
d1 = new Container("content");
console.log(d1.service());
console.log(d1.service());
console.log(d1.service());
console.log(d1.service());