In JavaScript, I may begin writing a ‘library’ or collection of functionality using a top level object like this:
window.Lib = (function()
{
return {
// Define Lib here.
//
};
})();
I may also add some functions within Lib which serve to create objects related to it:
window.Lib = (function()
{
return {
ObjectA: function()
{
var _a = 5;
return {
getA: function(){ return _a; }
};
},
ObjectB: function()
{
var _b = 2;
var _c = 1;
return {
getB: function(){ return _b; }
};
}
};
})();
Which would be used like so:
var thing = Lib.ObjectA();
var thing2 = Lib.ObjectA();
var thing3 = Lib.ObjectB();
And I can use the methods within each of those created above to get the values of _a defined within ObjectA() or _b defined within ObjectB():
alert(thing.getA()); // 5
alert(thing3.getB()); // 2
What I want to achieve is this:
Say I want to access the property _c (defined within ObjectB()) but only within the scope of Lib. How could I go about that? By this I mean, I want to make the property readable within any function that I define within the object returned by Lib(), but I don’t want to expose those values outside of that.
Code example:
window.Lib = (function()
{
return {
ObjectA: function(){ ... },
ObjectB: function(){ ... },
assess: function(obj)
{
// Somehow get _c here.
alert( obj.getInternalC() );
}
};
})();
Which would work like so:
var thing = Lib.ObjectB();
alert( thing.getInternalC() ) // error | null | no method named .getInternalC()
Lib.assess(thing); // 1
Hope this makes sense.
So you want per-instance protected properties? That is, properties on the instances created by
ObjectA,ObjectB, etc., but which are only accessible to the code within your library, and not to code outside it?You cannot currently do that properly in JavaScript, but you’ll be able to in the next version using private name objects. (See “Almost doing it” below for something similar you can do now in ES5, though.)
It’s easy to create data that’s shared by all code within
Lib, but not per-instance properties, like so:All of the functions defined within there (your
ObjectA, etc.) will have access to that onesharedDatavariable, which is completely inaccessible from outside. But it’s not per-instance, each object created byObjectA,ObjectB, etc. doesn’t get its own copy.Almost doing it
If your code will be running in an environment with ES5 (so, any modern browser, where “modern” does not include IE8 or earlier), you can have obscured but not actually private properties, via
Object.defineProperty. This is similar to how private name objects will work in ES.next, but not genuinely private:Live Example | Source
And use it like this:
The object returned by
Lib.ObjectAhas a property whose name will change every timeLibis loaded, and which is not enumerable (doesn’t show up infor-inloops). The only way to get at it is to know it’s name (which, again, changes every timeLibis created — e.g., every page load). The code withinLibknows what the property name is, because it’s in thecvariable which is shared by all of theLibcode. Since you can access properties using bracketed notation and a string, we can useinstance[c]to access the property.You see how these are pretty well obscured. Code outside of
Libdon’t see the obscured property when enumerating the property in the object, and they don’t know the semi-random name we assigned it, so can’t find the property. Of course, you could find it via inspection using a debugger, but debuggers can do lots of things.And in fact, this is how private properties will work in ES.next, except that
cwon’t be a string, it’ll be a private name object.