12

I was having a discussion with a fellow developer on whether hacking into javascript private functions makes sense or not.

Alternatives are:

  1. A constructor and a prototype with all the functions in, non-API methods(private) will be just named with an underscore _function_name so that devs know what can they call and what they cannot call.
  2. A constructor and a prototype for API functions, and free functions as private functions inside a private namespace that hides them from the rest of the namespaces except this one.

We do not consider other approaches, like creating private functions in the constructor of the form var private_var= function(){} because that would trigger the creation of all those functions each time an object gets instantiated and each object would have its own set.

Reasons we had for them:

1

  • Javascript does not support private functions per se, in fact, there is no concept of private/protected/public visibility, so this is basically a hack
  • Using the underscore in method names marks clearly what are the boundaries for the given class/prototype, there is no need for "enforcing" it, in fact languages like Python don't have private methods and python users never seemed to care about it apart from using underscores
  • Even if private gets enforced, what sense does it make in a language where you can just dynamically substitute public methods?
  • Affects readability, quite a lot, private functions are separated into another set of braces for their scope, they cannot use this or they need to be called with function.call(object) or function.apply(object)

2

  • Brings a clear limitation by encapsulating private methods far from the class/prototype user hands
  • It is more or less the industry standard, lots of javascript developers use it like that

We suspect that because lots of developers use it, there might be another reason, like performance or so, to be used like that.

As our knowledge of Javascript is quite limited, we decided to post this in stackoverflow to see what approach is better and why.

Arkaitz Jimenez
  • 22,500
  • 11
  • 75
  • 105
  • 3
    I don't see why you consider them to be a hack. Privacy (capsulation) in JS *is* done by closures, there's nothing wrong with that. "*each instance would have its own set*" is not a problem, but solved efficiently in modern js engines. Or did you really have performance/memory problem? – Bergi Oct 18 '12 at 05:50
  • @Bergi, well, they are not supported by the language, you are basically taking extra steps to workaround the absence of visibility into the language, thats what I would consider a hack. And no, I am not worries about performance, its just I need to take a decission and I would like it to be as complete as possible. – Arkaitz Jimenez Oct 18 '12 at 07:29
  • @ArkaitzJimenez one thing you should remember is that JS is not strictly OOP. It does at times have mechanics that resemble OOP type concepts, but I think many feel those features actually hurt the language. It is more akin to functional programming at times, and also has a prototypical inheritance model. So, saying that private does not exist and is a hack when using closures isn't accurate simply because we are in a different paradigm with JS. – Parris Oct 24 '12 at 04:09

10 Answers10

6

How would you hack into javascript private functions and for what purpose?

I think the different methods of creating classes, private functions, etc depend on your motivations.

The underscore convention helps when you try to unit test and you really want to break up what might look like a giant method from the outside.

I feel that in every other case you should try to make things truly private. If you are trying to expose a nice, clean API for others to work with they should not need to see what is behind the scenes. Why expose that? This leads to general convos about private and public: Why "private" methods in the object oriented?

You do have a few choices for privatizing methods and some of these choices impact performance.

Underscore convention:

function Pizza() {
   this._pepperoni = function () {};
}

or

function Pizza() {
}

Pizza.prototype._pepperoni = function () {};

Scoping

function Pizza() {
    function pepperoni() {};
}

Namespacing/Modules

var pizza = pizza || {};
(function() {
    function pepperoni() {};
    function create() {
        pepperoni();
    }
    window.pizza.create = create; // or module.export = pizza or both
}());

Module Pattern

(function(){
    function pepperoni() {};
    function Pizza() {
        pepperoni();
    }

    window.Pizza = Pizza;
}());

About recreating your functions vs defining them once. First if you would like to use internal private members and still use "this" just create a new variable called self and assign this to it:

function Pizza() {
    var self = this;
    function pep() {
       self.x = 1;
    }
}

Next, I attempted to test the performance difference between redefining and writing functions up front: http://jsperf.com/private-methods I think it saves you a little less than 20% on ops/sec to have your functions be recreated every time.

I am not recommending any approach, they are all valid and useful at various times. Sometimes it is more about semantics, sometimes it's about performance and other times it is to meet some end like unit testing.

Community
  • 1
  • 1
Parris
  • 17,833
  • 17
  • 90
  • 133
4
  • It is not a hack: I think it's fundamental to overcome this idea. When you're using a core legitimate feature of the language - closures - to achieve the goal of hiding the details of your objects then you're not hacking.

    It's important to note that when you use private in class-based languages, you're just implementing a higher-level concept which is to hide implementation details of your objects. With that in mind, we're not trying to imitate private modifier in javascript, we're just implementing a concept, how we implement it is not that relevant and is dependant on the tool/language.

    By the way, I come from a C# background and I found it very hard to overcome this "hack" barrier when I started with JavaScript, until recently, I considered closures, object literals, constructor functions, callback functions ... I considered them all hacks. Only when I overcame that mental barrier then I started appreciating JavaScript and writing good code that takes advantage of its strengths.

  • As to how hide your "private" functions, you could hide them inside a namespace like you suggested, or initialize as variables with Module Pattern or one of its variations which will be my preference. You said that this will mean that these variables will be recreated with every new instance, but that's the same for private variables in class-based language. If you're looking for an equivalent of static then you can just do MyClass.StaticVariable = "myStaticVariable" and that should be it.

  • What difference does it make to hide details in a dynamic language when you can change the public API? Well, this brings us back to my first point - looking into JavaScript with wrong eyes of class-based languages - from a dynamic language point of view, imagine all the flexibility you get because of that dynamic nature, I was just looking at Sinon library which provides ways to mock things like timers (basically because you can hijack the public api of almost everything), imagine how difficult that would be in a non-dynamic language, see all the need for mocking frameworks, IoC containers, Proxy generators, reflection, you get all of this for free in a dynamic language like JavaScript. So even though your argument is correct technically, when put into the full context then it becomes irrelevant.

    Again when hiding implementation details, we're not doing it to imitate C#/Java/C++ feature, we're doing it because firstly it's good design and good concept for reusability and maintenance, but secondly - and as important in my view - we do it because it's a language pattern and this is how it's done in JavaScript. Don't underestimate that, you write code today that will be read by someone else tomorrow, so following common patterns (of OO design as in hiding details and encapsulation, and language-specific patterns as in Module Pattern) greatly improve communication, which is - by itself - enough to embrace it in my opinion. If you do it the "JavaScript-way" then you're already communicating properly to other team members, to the JavaScript expert who will join the team in the future and also to the community.

  • As far as readability is concerned, you're doing readers of your code a favour by following patterns and common conventions. If you go and try to do the same in C++, only then you're affecting readability.

  • Do the underscore thingy: conventions are good especially when working with teams, and one of the biggest libraries jQuery UI uses this convention and it does work and make things much clearer. So do it, even if your variables are not really hidden (in jQuery UI, you could still access and modify the underscored variables), the clarity and consistency that it brings to your codebase is invaluable.

Last, I keep mentioning "do it the JavaScript way" but that statement itself is delusive. I think that there is a JavaScript way(s) for the problem you're mentioning but on a bigger scale, espcially at the level of frameworks and libraries, there is hardly a single way of doing things. But that's part of the excitement and beauty of JavaScript. Embrace it.

kabaros
  • 5,083
  • 2
  • 22
  • 35
3

Yes, it is a bad idea based on a misunderstanding. It is commonly misunderstood that languages like Java, C# and so on have privacy that is enforced or cannot be circumvented. But in reality that is completely false and the private and other access modifiers in Java, C# etc come down to advice and communication, not enforcement.

By Martin Fowler:

The point of access control is not to prevent access, but more to signal that the class prefers to keep some things to itself. Using access modifiers, like so many things in programming, is primarily about communication.

This is exactly what underscore prefix does. And with underscore prefixing, you are not fighting against the language object model.

You cannot circument the closures for any reason, but this is possible in every other language. Ironically all you have done is you have made Javascript the most inflexible language of them all.

Because you use variables and not object properties, you cannot have

Basically the OOP features you get with closures are pretty much limited to just grouping just a bunch of functions together. That is only good for initial toy examples. And if you insist against common sense that privacy must be enforced by the machine, then you don't even get to have "package private", "protected" or many kinds of more sophisticated levels of "access control".

Btw, you also need to create unique function objects (because they have observable identity) per each method per each instance.

Esailija
  • 138,174
  • 23
  • 272
  • 326
2

Which approach is better depends largely on what you are trying to achieve.

Your alternative 1 is an agreement of developers on a certain naming convention. This approach is better whenever you have a team of developers that are willing to commit on this agreement and they are the only ones using the piece of software. As you correctly state this approach supports readability and more important testability of your code very well. Also you will find a lot more developers that can understand and maintain the code than with alternative 2.

Your alternative 2, and any pattern for implementing real private members of objects with closures, is not a hack but the way javascript works. This approach is better whenever you really need to protect attributes inside your object. This is mostly the case when making the piece of code available to developers that are not part of your team or making it publicly available. But you will lose some readability and testability of your code and you will find less developers that can understand and maintain the code.

Also there seems to be some confusion about javascript on you side. You are correct about javascript not (yet) supporting private attributes. But javascript also does not support "classes" as a language construct and neither does it support "class methods". Everything in javascript is (just) an object. The class constructor is just a pattern for creating an object, and methods are (just) attributes of objects that are of type "function". Objects in javascript are not instances of classes, as in traditional object oriented languages.

So as you correctly state, after creation of an object in javascript, every attribute of that object, including function attributes aka methods, can be changed (except for attributes encapsulated in closures). This is the power of javascript but in case of protecting objects from change it is a disadvantage and not something javascript is (yet) designed for. You will not be able to prevent users from rewriting your objects, but you can make it more difficult with closures.

I hope this helps on your decision.

crackmigg
  • 5,571
  • 2
  • 30
  • 40
1

I would recommend using a tool from the next version of JavaScript, ES6: WeakMap. I've implemented this in IE8+ and I've written about it and use it extensively.

function createStorage(creator){
  creator = creator || Object.create.bind(null, null, {});
  var map = new WeakMap;
  return function storage(o, v){
    if (1 in arguments) {
      map.set(o, v);
    } else {
      v = map.get(o);
      if (v == null) {
        v = creator(o);
        map.set(o, v);
      }
    }
    return v;
  };
}


var _ = createStorage(function(o){ return new Backing(o) });

function Backing(o){
  this.facade = o;
}
Backing.prototype.doesStuff = function(){
  return 'real value';
}

function Facade(){
  _(this);
}
Facade.prototype.doSomething = function doSomething(){
  return _(this).doesStuff();
}

More information:

  1. http://bbenvie.com/articles/2012-07-25/JavaScript-Classes-with-private-protected-and-super
  2. http://benvie.github.com/WeakMap/
  3. http://benvie.github.com/harmony-collections/
0

Where I work, the recommended pattern is using the "namespacing pattern" and treating namespaces as you would in any OO language.

You can see how in this answer

Community
  • 1
  • 1
Codeman
  • 12,157
  • 10
  • 53
  • 91
0

I think private methods are good if you want to prevent other developers to access these methods even if they know they shouldn't.

please read this Crockford article, specially the part about OOP and private members

hope this help

0

I prefer using revealing module pattern. Check here

Sunny
  • 4,765
  • 5
  • 37
  • 72
0

Although this is not really an answer to the question of weather it is a good idea to strictly enforce private methods I'd just like to point out that it is possible to do so using a closure.

It's basically the var foo=function trick but it doesn't create a new function for each instance of the object. The way to do it is this:

// Create a closure that we can share with our constructor
var MyConstructor = (function(){

    // Within this closure you can declare private functions
    // and variables:
    var private_function = function () {};
    var private_var = {};        

    // Declare the actual constructor below:
    return function () {

    }
})()

Personally, I'm of two minds about this. Coming from a working environment with lots of people working on the same set of files at the same time I really appreciate the ability to make stuff really private so that code wouldn't be broken by people trying to use the object incorrectly.

On the other hand, coming from a Perl background I also appreciate the fact that the original programmer who designed the object is not omnipotent and can't forsee all the ways the code will be used in the future. Sometimes you really need to change an object's internals in some corner cases. This has always been the standard accepted wisdom of experienced Perl programmers.

In the end, both ways work. Most module in Perl's CPAN repository is very stable and works right out of the box even without real privacy. On the other hand I've worked on projects where people have introduced bugs because of it. I guess it boils down to how your team work together. If coding guidelines and culture is respected by everyone then the Perl style "_" trick works great. If on the other hand you can't trust how future maintainers will mangle your code then enforcing privacy more strictly is probably better.

slebetman
  • 109,858
  • 19
  • 140
  • 171
  • Thanks for this approach for private functions, however, the whole point is, why would you need to take extra measures to enforce private functions? specially when anybody can just override the public ones. – Arkaitz Jimenez Oct 18 '12 at 07:28
  • For one, to prevent them overriding private methods. Even in traditional OO public methods can always be replaced by subclassing. The point of private methods is that they can't be messed with. Of course, with Js, stashing private methods in a closure also prevents public methods from being overridden without breaking the object. That's because there's no way for the new method to access the closure so it won't have access to the private methods. – slebetman Oct 18 '12 at 08:15
  • Not in all the languages, in some public methods need to be marked virtual for that. Why would you break by overriding a public method? There is the fact that you won't be able to call the private functions from the method you are overriding, but that doesn't need to break anything, you could virtually replace every public method if you wanted to and create your own object, thats why I ask what sense does it make to hide privates when the user could rewrite part or the whole class to his needs, also note that the code is still there, so he could always just copy that into a new method. – Arkaitz Jimenez Oct 18 '12 at 08:19
0

There are several approaches to your problem, and which one you choose depends on a few factors, including (1) target browser support, (2) project goals, and (3) personal preference. I'll highlight a few approaches on which I have opinions in particular.

Symbols

I highlight this one first because it is the most robust solution, and it's the future of JavaScript: it will be included in the upcoming version of the ECMAScript standard. It is possible today with a shim in ES5 compliant browsers. That means it works in basically all A-grade browsers released in the past 2 years. The main down-side is it's not supported in IE 8, but it is supported in IE 9 and 10 (and of course all modern versions of FF, Chrome, and Safari). If IE8 still matters to you, this isn't an option for you yet.

The shim can be downloaded here: SymbolsForES5. This library makes it possible for you to start using this feature, and when Symbols are natively included in browsers in the future, your code should be able to transition nicely.

Here's an example of using Symbols for private members:

var x = { };
var a = new Symbol();
x[a] = 5;
console.log(x[a]); // => 5

As long as you have access to the a Symbol object, you can read the property from the x object, but if anyone who doesn't have access to a can't read it. This allows you to really have private members:

var Person = (function() {

    var firstName = new Symbol(),
        lastName = new Symbol();

    function Person(first, last) {
        this[firstName] = first;
        this[lastName] = last;
    }

    Person.prototype.getFullName = function() {
        return this[firstName] + ' ' + this[lastName];
    };

    return Person;

})();

var john = new Person('John', 'Smith');
john.getFullName(); // => 'John Smith'

Object.getOwnPropertyNames(john); // => [ ]

Using a DON'T ACCESS Character

As you mentioned, you can always prefix a property with a character (such as underscore) to indicate that it shouldn't be accessed by external code. The main drawback is the property is still accessible. There are some good benefits, however: (1) efficient memory (2) full ability to use prototypal inheritance (3) easy to use (4) easy to debug (since the properties show up in a debugger) (5) works in all browsers.

I have used this method extensively in the past to great success. As an alternative to the underscore, in one framework I developed (joi), I used the # symbol because it makes the property harder to access (you have to access it with square bracket notation instead), serving as a gentle reminder to anyone trying to access it that it really probably should be left alone:

function Person(first, last) {
    this['#firstName'] = first;
    this['#lastName'] = last;
}

Person.prototype.getFullName = function() {
    return this['#firstName'] + ' ' + this['#lastName'];
};

var john = new Person('John', 'Smith');
john.getFullName(); // => 'John Smith'

I've used this technique for around 7 years now to great success, and would highly recommend it if Symbols don't suit your needs.

Privates Inside the Constructor

I know you said you decided not to go with this technique due to memory/performance reasons, but if something close to true privates are what you want and you can't use Symbols because you need legacy browser support, it's a good option. The company I work for uses this model on large-scale applications, and the memory consumed really isn't a problem. In addition, I have heard of studies which have discovered ways to optimize for memory and performance in this model, and I believe modern browsers (at least V8/Chrome, if not others) are starting to implement these optimizations. (This information comes from a talk I heard from Brendan Eich; I'm sorry I don't know which talk it was off the top of my head.)

In the end, there are experts which advocate the use of this technique, and while it's not my preference, my company has had success with it, and I can vouch for it as a reliable model.

For completeness, it looks like this:

function Person(first, last) {
    this.getFullName = function() {
        return first + ' ' + last;
    };
}

var john = new Person('John', 'Smith');
john.getFullName(); // => 'John Smith'

A JavaScript engine can optimize this by not really creating a new function for each getFullName method (even though, by the book, it's supposed to), since in this case there's no way to determine whether it actually creates a new function object each time. The tricky part is once code is introduced which would be able to determine whether a new function object is created each time, the engine needs to switch over to actually do that.

WeakMaps

In another answer benvie (mentioned WeakMaps)[http://stackoverflow.com/a/12955077/1662998]. I would consider this alternative as well if IE8 support is needed and you want the properties to really simulate private members.

Nathan Wall
  • 10,530
  • 4
  • 24
  • 47