Private instance variables available everywhere within constructedobject

B

Brett

Hi,

I'd like to get some feedback from more seasoned persons on an
approach I've used to make private instance variables available
anywhere within an object's methods (the constructor or prototype
methods), and building on another approach which allows private
instance methods anywhere within an object's methods. It adds a bit of
code ugliness and, as with prototype overriding, has a security issue,
but I think it may be well worth using in many cases.

My own post is at http://brettz9.blogspot.com/2009/01/i-came-across-this-very-clever-method.html

The post on private instance methods (which I reference in my blog) is
by Andrea Giammarchi and is at:
http://webreflection.blogspot.com/2008/04/natural-javascript-private-methods.html
..

I'd be interested to know if this approach has been used before, and
if so, what other uses or concerns it may raise. (I'm intrigued also
by the potential I didn't mention in the blog post about methods being
able to access or alter the private instance variables across any or
all instances.)
 
R

RoLo

Hi,

I'd like to get some feedback from more seasoned persons on an
approach I've used to make private instance variables available
anywhere within an object's methods (the constructor or prototype
methods), and building on another approach which allows private
instance methods anywhere within an object's methods. It adds a bit of
code ugliness and, as with prototype overriding, has a security issue,
but I think it may be well worth using in many cases.
don't know if I'm missing something but what I see is something like:

function()
{
var private;
function Constructor()
{
var usePrivate=private;
};
Constructor.prototype.method=function(){var
usePrivateAgain=private;};
return Constructor;
}();

which would be a normal use of closures... I didn't studied too much
the code so maybe I'm missing something.
 
B

Brett

don't know if I'm missing something but what I see is something like:

function()
{
  var private;
  function Constructor()
  {
  var usePrivate=private;
  };
  Constructor.prototype.method=function(){var
usePrivateAgain=private;};
  return Constructor;

}();

which would be a normal use of closures... I didn't studied too much
the code so maybe I'm missing something.

Hi,

It achieves instance variables using the same technique as normal
static variables, but it offers a way to do so in a fashion which
varies with each instance--unlike a normal use of closures.

To adapt your example slightly:

var Constructor = function()
{
var priv;
function Constructor(privVar)
{
priv = privVar;
};
Constructor.prototype.get=function() {return priv;}
return Constructor;
}();
var a = new Constructor('a');
var b = new Constructor('b');
alert(a.get()) // This should give 'a' if this were an instance
variable, but it is 'b'

By incrementing a static counter on each call of the constructor and
then using that index as a reference in which to store and access that
instance's private variables, we can ensure that each instance has its
own copy (but without exposing it (except if a method is deliberately
added which exposes the variable or if someone tampers with obj._$)).
Basically, I think it is more effective than simply prepending '_'.
I'm already using it in code, and it helps make things clear, if you
can just ignore the ugly line at the top of each method that needs the
private variable.

var Constructor = function()
{
var _$ = 0, __ = []; // Paste this at the top
function Constructor(privVar) { this._$=_$; _$++; var _=__[this._$]=
{}; // Paste this at the top of each constructor
_.priv = privVar;
};
Constructor.prototype.get=function() {var _=__[this._$]; // Paste
this at the top of each method as a shortcut
return _.priv;
}
return Constructor;
}();
var a = new Constructor('a');
var b = new Constructor('b');
alert(a.get()) // 'a'
alert(b.get()) // 'b'

It's still possible to access the whole static array (and the objects
in which each set of variables is stored).

var Constructor = function() {
var _$ = 0, __ = []; // Paste this at the top
function Constructor(privVar) { this._$=_$; _$++; var _=__[this._$]=
{}; // Paste this at the top of each constructor
_.priv = privVar;
};
Constructor.prototype.get=function() {var _=__[this._$]; // Paste
this at the top of each method as a shortcut
return _.priv;
}
Constructor.prototype.assimilate=function() { // Could also be done
as a class method
for (var i=0; i < __.length; i++) {
__.priv = 'Borg';
}
}
return Constructor;
}();
var a = new Constructor('a');
var b = new Constructor('b');
b.assimilate();
alert(a.get()) // 'Borg'
alert(b.get()) // 'Borg'

While this may be a bug or a feature, according to your tastes, even
though it exposes the instances to some degree, it is much less likely
to be accidentally tampered with by trusted consumers than other
conventions might be.
 
R

RoLo

don't know if I'm missing something but what I see is something like:
function()
{
  var private;
  function Constructor()
  {
  var usePrivate=private;
  };
  Constructor.prototype.method=function(){var
usePrivateAgain=private;};
  return Constructor;

which would be a normal use of closures... I didn't studied too much
the code so maybe I'm missing something.

Hi,

It achieves instance variables using the same technique as normal
static variables, but it offers a way to do so in a fashion which
varies with each instance--unlike a normal use of closures.

To adapt your example slightly:

var Constructor = function()
{
  var priv;
  function Constructor(privVar)
  {
  priv = privVar;
  };
  Constructor.prototype.get=function() {return priv;}
  return Constructor;}();

var a = new Constructor('a');
var b = new Constructor('b');
alert(a.get()) // This should give 'a' if this were an instance
variable, but it is 'b'

By incrementing a static counter on each call of the constructor and
then using that index as a reference in which to store and access that
instance's private variables, we can ensure that each instance has its
own copy (but without exposing it (except if a method is deliberately
added which exposes the variable or if someone tampers with obj._$)).
Basically, I think it is more effective than simply prepending '_'.
I'm already using it in code, and it helps make things clear, if you
can just ignore the ugly line at the top of each method that needs the
private variable.

var Constructor = function()
{
  var _$ = 0, __ = []; // Paste this at the top
  function Constructor(privVar) { this._$=_$; _$++; var _=__[this._$]=
{}; // Paste this at the top of each constructor
      _.priv = privVar;
  };
  Constructor.prototype.get=function() {var _=__[this._$]; // Paste
this at the top of each method as a shortcut
        return _.priv;
    }
  return Constructor;}();

var a = new Constructor('a');
var b = new Constructor('b');
alert(a.get()) // 'a'
alert(b.get()) // 'b'

It's still possible to access the whole static array (and the objects
in which each set of variables is stored).

var Constructor = function() {
  var _$ = 0, __ = []; // Paste this at the top
  function Constructor(privVar) { this._$=_$; _$++; var _=__[this._$]=
{}; // Paste this at the top of each constructor
      _.priv = privVar;
  };
  Constructor.prototype.get=function() {var _=__[this._$]; // Paste
this at the top of each method as a shortcut
        return _.priv;
  }
  Constructor.prototype.assimilate=function() { // Could also be done
as a class method
      for (var i=0; i < __.length; i++) {
        __.priv = 'Borg';
      }
  }
  return Constructor;}();

var a = new Constructor('a');
var b = new Constructor('b');
b.assimilate();
alert(a.get()) // 'Borg'
alert(b.get()) // 'Borg'

While this may be a bug or a feature, according to your tastes, even
though it exposes the instances to some degree, it is much less likely
to be accidentally tampered with by trusted consumers than other
conventions might be.


ok... this pattern is not new for me at least. Have already done stuff
like this for quite some time ago...
never the less, thanks for the tip.
 
R

RobG

don't know if I'm missing something but what I see is something like:
function()
{
  var private;
  function Constructor()
  {
  var usePrivate=private;
  };
  Constructor.prototype.method=function(){var
usePrivateAgain=private;};
  return Constructor;

which would be a normal use of closures... I didn't studied too much
the code so maybe I'm missing something.

Hi,

It achieves instance variables using the same technique as normal
static variables, but it offers a way to do so in a fashion which
varies with each instance--unlike a normal use of closures.

To adapt your example slightly:

var Constructor = function()
{
  var priv;
  function Constructor(privVar)
  {
  priv = privVar;
  };
  Constructor.prototype.get=function() {return priv;}
  return Constructor;}();

var a = new Constructor('a');
var b = new Constructor('b');
alert(a.get()) // This should give 'a' if this were an instance
variable, but it is 'b'

By incrementing a static counter on each call of the constructor and
then using that index as a reference in which to store and access that
instance's private variables, we can ensure that each instance has its
own copy (but without exposing it (except if a method is deliberately
added which exposes the variable or if someone tampers with obj._$)).
Basically, I think it is more effective than simply prepending '_'.
I'm already using it in code, and it helps make things clear, if you
can just ignore the ugly line at the top of each method that needs the
private variable.

var Constructor = function()
{
  var _$ = 0, __ = []; // Paste this at the top
  function Constructor(privVar) { this._$=_$; _$++; var _=__[this._$]=
{}; // Paste this at the top of each constructor

If the intention is to demonstrate a concept, surely it is better to
give variables meaningful names (e.g. something that mirrors either
their purpose or the data they hold) than to use meaningless symbols?

The $ symbol in particular seems to be abused greatly - some seem to
think it is an alias for a "get element" type verb, others for "this
is a variable".

What is its meaning here?

[...]
While this may be a bug or a feature, according to your tastes,

A bug is where code does not do what it is intended to do. Closures
are not bugs, therefore they are a feature.

even
though it exposes the instances to some degree, it is much less likely
to be accidentally tampered with by trusted consumers than other
conventions might be.

It is more likely not to be tampered with because of the meaningless
symbols used for names, e.g. $, _, __, _$ and so on.
 
B

Brett

It achieves instance variables using the same technique as normal
static variables, but it offers a way to do so in a fashion which
varies with each instance--unlike a normal use of closures.
To adapt your example slightly:
var Constructor = function()
{
  var priv;
  function Constructor(privVar)
  {
  priv = privVar;
  };
  Constructor.prototype.get=function() {return priv;}
  return Constructor;}();
var a = new Constructor('a');
var b = new Constructor('b');
alert(a.get()) // This should give 'a' if this were an instance
variable, but it is 'b'
By incrementing a static counter on each call of the constructor and
then using that index as a reference in which to store and access that
instance's private variables, we can ensure that each instance has its
own copy (but without exposing it (except if a method is deliberately
added which exposes the variable or if someone tampers with obj._$)).
Basically, I think it is more effective than simply prepending '_'.
I'm already using it in code, and it helps make things clear, if you
can just ignore the ugly line at the top of each method that needs the
private variable.
var Constructor = function()
{
  var _$ = 0, __ = []; // Paste this at the top
  function Constructor(privVar) { this._$=_$; _$++; var _=__[this.._$]=
{}; // Paste this at the top of each constructor

If the intention is to demonstrate a concept, surely it is better to
give variables meaningful names (e.g. something that mirrors either
their purpose or the data they hold) than to use meaningless symbols?

Usually yes, unless you intend to shorten things for those who might
use something frequently, as this is intended. If I had used a longer
version, some might have complained that the approach was too
cumbersome to be useful (no doubt, maybe even now, some will feel that
way). And the blog post I originally referenced has a little more
context in the comments. But fair enough--see below for an
explanation.
The $ symbol in particular seems to be abused greatly - some seem to
think it is an alias for a "get element" type verb, others for "this
is a variable".

Yes. It'd be nice if there were more symbols that could be used in JS
to avoid their being overloaded for too many purposes. But if there
were more, there'd no doubt be more conventions that would accumulate
around them--something which I don't think is necessarily a bad thing,
but which does take some awareness in the community, as with many
convenient features.
What is its meaning here?

Ok, to explain the arcane symbols' usage...

The double underscore, '__' is an array used to hold each set of
instance variables. Underscores are commonly used as prefixes on
private variables. I used a double underscore here to distinguish it
from the more convenient single underscore shortcut (explained below)
that can be reused throughout the code, and by being longer, it helps
reinforce the fact that it can contain a multiplicity of private
variables.

The static '_$' is a unique counter (maybe the dollar sign can conjure
up numbers, as a kind of mnemonic device) which should always go up by
one in the constructor, as I've done (and not be tampered with
elsewhere), while "this._$" should reflect the current instance's
index. You can think of '_$' as a count of the total number of objects
so far created, while this._$ indicates the ordinality of the current
object (whether it is the first one (index 0), the second one (index
1), etc.).

Therefore, when this._$ is used as an index on the static '__' array
(i.e., "__[this._$]" which we quickly abbreviate to just '_' and use
that shortcut throughout our code), it locates a unique place on the
static array which we will consider to belong to that instance only.
Whenever we call the constructor to build our object, the constructor
also creates an empty object on the static '__' array to hold the
present instance's set of instance variables in place for us.

We can, thus, after the first line in our constructor, create a
private instance variable like this:

__[this._$]['myPrivateVar'] = 5;

or if our variable uses all legal identifier characters, use this:

__[this._$].myPrivateVar = 5;

or if we're using the shortcut assignment (var _=__[this._$]) we
defined in our code, we can use just this:

_['myPrivateVar'] = 5;

or simply:

_.myPrivateVar = 5;

Note that the shortcut needs to be defined (preferably at the top) of
each function that needs the shortcut. I like to put it on the same
line as the function (as I like to do with the constructor
initialization code), so that it isn't as distracting when trying to
look at the main code at hand:

myFunction : function () { var _=__[this._$];
_.somePrivateVar = 3;
}

Also one should notice that in our shortest form, there must be a '.'
after the underscore, since we're accessing an object. Often code may
have something like "_myPrivateVar", but this is just a convention and
offers no real privacy. Our approach extends a little on this
convention, but affords a certain degree of real privacy.

[...]
While this may be a bug or a feature, according to your tastes,

A bug is where code does not do what it is intended to do.  Closures
are not bugs, therefore they are a feature.

My point was that we were using a closure to achieve instance
variables, and not using them for creating regular (instance-
independent) static variables (which behaves more similarly to its
classical object-oriented language counterpart). People used to
classical OOP might not like the fact that there is a way that one
object's "instance" variables can be accessed by another object
(though it is unlikely to do this by accident), and thus call it a
"bug".

While strictly speaking, a bug may be going against the author's
designs, if code behaves contrary to convention or common terminology,
people may still report it as a bug--thus the tongue-in-cheek
expression about "It's a feature not a bug".
It is more likely not to be tampered with because of the meaningless
symbols used for names, e.g.  $, _, __, _$ and so on.

The meaningless symbols do help to some degree, and are deliberately
chosen for this reason. Sometimes in multi-programmer environments (or
even within just one's own code), it is helpful to prevent programmers
from being tempted to tinker with private variables, and force them to
go through the public API. But, unlike cases where people ONLY say add
the '_' prefix to their so-called "private" variables, our code has
only two access points to our private "instance" variables:
1) Someone could externally tamper with the regrettably but
unavoidably public "_$" counter variable added to each object
instance. But they shouldn't be able to get direct access to the
contents of that instance's private variables, unless the API exposes
them--only to its instance ordinality.
2) Someone could use or add a method within our class which tampers
with or accesses the __ array or the static _$ counter, contrary to
their intended usage. But then they'd have to be in control of our
class itself and probably deliberately be messing things up.

So, given the above, I think this situation is safer and more clear
than having a multiplicity of "_XXX" variables which are intended to
be private, but any one of which can be accidentally overridden or
directly utilized externally (contrary to the author's intentions).
But the privacy comes at the price of having to repeat some ugly code
in a number of places.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top