Skip to content

Instantly share code, notes, and snippets.

@Integralist
Last active March 26, 2020 23:27
Show Gist options
  • Save Integralist/8419151 to your computer and use it in GitHub Desktop.
Save Integralist/8419151 to your computer and use it in GitHub Desktop.
Private and Privileged methods using the Constructor pattern in JavaScript
function Constructor(){
this.foo = 'foo';
// Needed for Private methods
var self = this;
// Private methods need to be placed inside the Constructor.
// Doesn't perform as well as prototype methods (as not shared across instances)
function private(){
console.log('I am private');
console.log(self.foo);
}
// Privileged methods need to be placed inside the Constructor.
// This is so they can get access to the Private methods.
this.privileged = function(){
private();
};
}
Constructor.prototype.public = function(){
console.log('I am public');
};
constructor = new Constructor;
console.log(constructor.foo);
constructor.public(); // will work
constructor.privileged(); // will work
constructor.private(); // won't work (can't be accessed directly)
@getify
Copy link

getify commented Jan 14, 2014

In class-oriented terminology, the third traditional "visibility" level between public and private is protected, which means available ONLY to the class itself or any of its descendents (not publicly).

The use of privileged here is different from protected (which isn't really possible in JS), but IMO it's kind of an unfortunate similar-but-not collision. privileged() wouldn't be accessible publicly as shown here if in fact it was protected visibility. Put another way, privileged() is more capable than protected should be.

But, the other confusion here is actually that in traditional classes, public methods can do what you've shown privileged() here do, which means your public() is less capable than public should be.

Mimicking these class-oriented concepts in JS quite often just abuses what the terminologies usually mean, and IMO that leads to a lot more confusion than it's worth.

@millermedeiros
Copy link

remind that private variables/functions in JS are not such a good idea in many cases - if you don't want a method to be accessed name the property starting with _, we are all grown ups, assume other devs knows what they are doing.

@jslegers the main drawback of functions added inside the constructor is that it uses more memory/cpu when you have multiple instances (creates a new function for each instance), while if you set methods on the prototype same function will be shared by all instances. It is also weird to have a lot of code inside the constructor, makes it harder to understand what is actually executed during instantiation - favor prototype when possible.

@jslegers
Copy link

@ millermedeiros :

Readability is a matter of taste. If you're more experienced with other programming languages (eg. PHP or Java), prototype syntax is confusing.

At this moment, I'm leaning towards this syntax (see also http://stackoverflow.com/questions/6590420/function-object-properties-piercing-the-veil/20734313#20734313) :

var keyValueStore = (function() {
    var count = 0; // Singleton private properties

    var kvs = function() {
        count++; // Instance private properties
    };

    kvs.prototype = { // Instance public properties
        'data' : {},
        'get' : function(key) { return this.data[key]; },
        'set' : function(key, value) { this.data[key] = value; },
        'delete' : function(key) { delete this.data[key]; },
        'getLength' : function() {
            var l = 0;
            for (p in this.data) l++;
            return l;
        }
    };

    return  { // Singleton public properties
        'create' : function() { return new kvs(); },
        'count' : function() { return count; }
    };
})();

Example usage:

kvs = keyValueStore.create();
kvs.set('Tom', "Baker");
kvs.set('Daisy', "Hostess");
var profession_of_daisy = kvs.get('Daisy');
kvs.delete('Daisy');
console.log(keyValueStore.count());

With this syntax, you can have :

  • multiple instances of an object
  • private properties
  • class properties
  • access to private variables from within your public methods

Any downsides besides readability? I'd love to know about them...

@getify
Copy link

getify commented Jan 14, 2014

@jslegers

What does

count++; // Instance private properties

...purport to mean? You say that count++ is an example of "instance private properties", but of course that's not true. count (as you indicated in your other comment) is shared across all instances, or what you call a "singleton property". (btw, this seems like a strange usage of the word "singleton" which doesn't match with the typical definition of that word -- "shared" is a better, less confusing term here IMO).

So, if count is not actually an "instance private property", then what are examples of "instance private properties" that could be added here? In this pattern, how could you setup a private variable that only each instance could access (and not be shared across instances), that not only the kvs() "constructor" function could access, but all his member methods like set() and delete() could also access?

@millermedeiros
Copy link

@jslegers if you want to mimic Java/PHP you can use a lib like dejavu, which implements accessor keywords; or use a language that compiles into JavaScript - but to be honest I would just stick with plain JS and avoid real private methods. (easier to debug and to extend code if needed)

"always bet on JS."

it's also good to remind that functional programming makes a few tasks way simpler and avoids bureaucracy. Not all the things needs to be a constructor! cheers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment