Posts Tagged ‘closure’

Constants

Saturday, April 10th, 2010

Although there actually are constants in some environments, e.g. in Firefox you can use const instead of var, in general in JavaScript there are no constants.

Workaround

To work around that limitation, people often use ALLCAPPS to denote "hey, don't touch this var, it's meant to be a constant". It's constant-by-convention but the values can be changed by careless programmer on a bad day. If you really want to protect the value, you need to make it private.

PHP-inspired API

In PHP there are the functions define(name, value) to gefine a constant, defined(name) to check if a constant is defined and constant(name) to get the value of a constants when it's name is assembled at runtime and you don't know it a priori. So I thought - well, we can do the same in JavaScript. Only, let's not use global functions, but a constant global var and make the functions method of that global. constant.constant(name) is a little mouthful, so let's make that one constant.get(name)

Implementation

Here's the simple implementation:

"use strict";
 
var constant = (function () {
    var constants = {},
        ownProp = Object.prototype.hasOwnProperty,
        allowed = {
            string: 1,
            number: 1,
            boolean: 1
        };
    return {
        define: function (name, value) {
            if (this.defined(name)) {
                return false;
            }
            if (!ownProp.call(allowed, typeof value)) {
                return false;
            }
            constants[name] = value;
            return true;
        },
        defined: function (name) {
            return ownProp.call(constants, name);
        },
        get: function (name) {
            if (this.defined(name)) {
                return constants[name];
            }
            return null;
        }
    };
}());

This is it. Basically protect an object in a closure and don't provide means to change it, but only to add properties to it.

UPDATE: thanks to the comments (see below), there's extra care to check for own properties of the constants private object. This allows to define constants with weird names such as toString and hasOwnProperty. Also only primitive values are allowed to be constants.

Usage

// check if defined
constant.defined("bazinga"); // false
 
// define
constant.define("bazinga", "Bazinga!"); // true
 
// check again
constant.defined("bazinga"); // true
 
// attempt to redefine
constant.define("bazinga", "Bazinga2"); // false
 
// was it constant or it changed?
// get da, get da, get da value
constant.get("bazinga"); // "Bazinga!"