JavaScript Object Encapsulation

by andrewdavey

JavaScript

// Helper function to create a proxy object that will pass on calls
// to public functions of the target object.
var createProxy = function (type) {
    // Create a new Proxy type for the type
    var Proxy = function(target) {
        this.target = target;
    };
    
    // Add all the public functions to the Proxy.
    for (var prop in type.prototype) {
        (function(prop) {
            if (type.prototype[prop].isPublic) {
                Proxy.prototype[prop] = function() {
                    // Call the original function of the target.
                    this.target[prop].apply(this.target, arguments);
                };
            }
        }(prop));
    }
    
    return Proxy;
};
// Helper function to mark a function as public.
var public = function(f) {
    f.isPublic = true;
    return f;
};
var Class = function(members) {
    var Proxy, constructor;
    function Type() {
        constructor.apply(this, arguments);
        return new Proxy(this);
    }
    for (var property in members) {
        if (property === "constructor") {
            constructor = members[property];
        } else {
            Type.prototype[property] = members[property];
        }
    }
    Proxy = new createProxy(Type);
    return Type;
};

var Foo = Class({
    constructor: function() {
        this.value = 42;
    },
    
    // note the "public" marker applied to this function
    magic: public(function() {
        alert('Reading secret value: ' + this.secret());
    }),
    
    // this is a private function
    secret: function() {
        return this.value;
    }
});

var p = new Foo();
p.magic();

if (("secret" in p) === false) {
    alert("secret function not publicly visible.");
}
if (("value" in p) === false) {
    alert("value property not publicly visible.");
}