JavaScript objects and Crockford’s The Good Parts

encapsulationinheritancejavascript

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?

Best 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.