Constants
Saturday, April 10th, 2010Although 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!"