Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I've been thinking quite a bit about how to do OOP in JS, especially when it comes to encapsulation and inheritance, recently.

According to Crockford, classical is harmful because of new(), and both prototypal and classical are limited because their use of constructor.prototype means you can't use closures for encapsulation.

Recently, I've considered the following couple of points about encapsulation:

  1. Encapsulation kills performance. It makes you add functions to EACH member object rather than to the prototype, because each object's methods have different closures (each object has different private members).

  2. Encapsulation forces the ugly "var that = this" workaround, to get private helper functions to have access to the instance they're attached to. Either that or make sure you call them with privateFunction.apply(this) everytime.

Are there workarounds for either of two issues I mentioned? if not, do you still consider encapsulation to be worth it?

Sidenote: The functional pattern Crockford describes doesn't even let you add public methods that only touch public members, since it completely forgoes the use of new() and constructor.prototype. Wouldn't a hybrid approach where you use classical inheritance and new(), but also call Super.apply(this, arguments) to initialize private members and privileged methods, be superior?

share|improve this question
    
I think there are some JavaScript libraries that provide all this, e.g. Dojo. There's also TypeScript. –  MarkJ Nov 1 '12 at 14:09
    
@MarkJ Dojo's class-system seems identical to the gazillion pseudo-classical inheritance libraries, and doesn't offer anything with regard to encapsulation. –  Jonathan Nov 1 '12 at 14:48
    
Btw, that article is downplaying the memory usage. It doesn't consider at all that the memory usage increases with the amount of methods.. e.g. if he had 20 methods on the "class", the functional pattern would take 3000 mb with his numbers but the prototypal would still take 150mb regardless of the amount of methods. It's like comparing O(1) to O(n) with n = 2... –  Esailija Nov 2 '12 at 19:21
add comment

1 Answer

Encapsulation is really tricky, and probably not worth the effort in JavaScript. A method that works, and does everything you would wish (private fields, access to the superclass and private methods) would be this (probably very ugly and improvable) solution:

function SomeClass() {

    var parent = SomeSuperClass(),
        somePrivateVar;

    return Object.create(parent, {
        somePrivateVar: {
            get: function() {
                return somePrivateVar;
            },
            set: function(value) {
                somePrivateVar = value;
            }
        },
        doSomething: {
            value: function(data) {
                someHelperFunction.call(this, data);
            }
        }
    });
}

function someHelperFunction(data) {
    this.someMethod(data);
}

This sort of works, allows you to have private fields and methods and inheritance as one would expect it. However, I don't like it - but I like it the best of all possibilities you have in pure JavaScript.

If I had to start a new project with a lot of JavaScript, I probably would have a closer look at TypeScript. It improves JavaScript where necessary (IMHO), gives you static typing, inheritance, encapsulation and everything.. But is just JavaScript, after all.


Now, is it worth it? I think there are two important things to consider. Encapsulation probably helps you at development time, but certainly doesn't at runtime. I think you have to decide; Either no encapsulation and better performance, or encapsulation, not-so-beautiful code, probably a better design but some overhead at runtime.

share|improve this answer
    
I'm aware of this pattern: it's what Crockford calls functional, with the slight difference that you set the parent as the child's prototype. The question is precisely: is the encapsulation worth the overhead mentioned in my OP (and present in your code)? Is there any way of getting around said overhead? TypeScript does seem interesting because the encapsulation checking is done at compile-time, which means there is no overhead in the compiled JS, but for the time being, I'm sticking with raw JS. BTW, for consistency, your code should probably read var parent = SomeSuperClass(), without new. –  Jonathan Nov 1 '12 at 14:57
    
@Jonathan: I added some more information on the "worth" question. –  Vain Fellowman Nov 2 '12 at 8:41
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.