Create a read-only/immutable copy of any object (including deep properties)

constants, immutability, javascript, object, readonly

Solution

This is the solution I came up with after some thought. Works well for my needs so I thought I'd share it QnA style. Do suggest any improvements/issues if you you find them.

/**
 * Make the the specified object (deeply) immutable or "read-only", so that none of its
 * properties (or sub-properties) can be modified. The converted object is returned.
 * @param {object} obj Input object
 */
makeImmutable: function makeImmutable (obj) {
    if ((typeof obj === "object" && obj !== null) ||
        (Array.isArray? Array.isArray(obj): obj instanceof Array) ||
        (typeof obj === "function")) {

        Object.freeze(obj);

        for (var key in obj) {
            if (obj.hasOwnProperty(key)) {
                makeImmutable(obj[key]);
            }
        }
    }
    return obj;
}

EDIT: Simplified the code. Also handles arrays correctly now.

Problem

How can I create a read-only/immutable version of an object in JavaScript, whose properties cannot be changed? This this should also apply to the properties of any sub objects and so on. All methods I have come across to do this (`Object.defineProperty`, `Object.freeze`, etc) work only for the top level properties of the object, but not for the sub-objects. (A possible use case: After creating/modifying a `settings` or `configuration` type object in a specific module, you need to expose it to the rest of the program's modules in an immutable form.)

Original source