How to write constants in javascript

YOU CAN’T. As simple as that. Anyway, what is a constant? A constant is a unchangeable variable that throws an error when you try to write in it. Thus, implementing constant in javascript would be against its will to be opened. The magic of javascript resides in the liberty it gives you to change anything you want, anywhere you want. Even if you’re not the owner of the object. Even if it’s a javascript intrinsic class. Why would you want to have constants???

Still, everyone wants to use constants (myself included). Here are a couple of ways of doing it without actually doing “it”.

Global constants

Ouch! That one hurts! As I said earlier, global variables are prohibited since 1992 by GVIP (Global Variables International Police). But sometimes, a man gotta do what a man gotta do. If you really can’t find any better solution, use this one.

[source:javascript]
var DISPLAY_TYPE_SMALL = 0;
var DISPLAY_TYPE_BIG = 1;
[/source]

Class constant

If you already know how to create objects you have to use the class functions technique (also knows as static or shared functions) to create a class “constant”.

[source:javascript]
// Create the class
function TheClass() {
}

// Create the class constant
TheClass.THE_CONSTANT = 42;

// Create a function for TheClass to alert the constant
TheClass.prototype.alertConstant = function() {
// You can’t access it using this.THE_CONSTANT;
alert(TheClass.THE_CONSTANT);
}

// Alert the class constant from outside
alert(TheClass.THE_CONSTANT);

// Alert the class constant from inside
var theObject = new TheClass();
theObject.alertConstant();
[/source]

As you saw, you can’t access the constant using the this variable (a reference to the current object) because the constant is defined on the class only and not the object.

Class enum

Sometimes, constants are not enough. You need to regroup them to be more logical. Example? I have three different display type : small, medium, big. I could do this

[source:javascript]
// Create the class
function TheClass() {
// Initialize the display type to big
this.displayType = TheClass.DISPLAY_TYPE_BIG;
}

// Create constants
TheClass.DISPLAY_TYPE_SMALL = 0;
TheClass.DISPLAY_TYPE_MEDIUM = 1;
TheClass.DISPLAY_TYPE_BIG = 2;

// Assign the small display type to the object
var theObject = new TheClass();
theObject.displayType = TheClass.DISPLAY_TYPE_SMALL;
[/source]

It works but they are not logically grouped. I would prefer to use an enumeration (enum) [more info about enum].

[source:javascript]
// Create the class
function TheClass() {
// Initialize the display type to big
this.displayType = TheClass.DISPLAY_TYPE.big;
}

TheClass.DISPLAY_TYPE = {
small : 0,
medium : 1,
big : 2
}

// Assign the small display type to the object
var theObject = new TheClass();
theObject.displayType = TheClass.DISPLAY_TYPE.small;
[/source]

This is what I call beautiful code.

One simple rule

Knowing that there’s no mechanism that prevents you from modifying your “constants”, follow that simple law : don’t modify your constants.

  • Abeckels
    Umm ... just use a function like a constant...

    function SELECTED() { return true; }
  • That's a good idea. Just don't forget the parenthesis : SELECTED() and not SELECTED.
  • Dennis
    Taken directly from the reference at: https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Statements/const

    "const is a Mozilla-specific extension, it is not supported by IE, but has been partially supported by Opera since version 9.0 and Safari."

    Until it is supported by browsers with a total marketshare of say 50%, it might as well not exist, so many thanks to the author and to the posters who shared some interesting approaches to getting the functionality of constants in a language that doesn't support them.
  • Dave
    Haha.. interesting to see how many acutally read the article. It almost gets to the point that a writer needs to write 500 words of caveats and legal mumbo jumbo before posting. Hahah..

    Thanks for the great article. It was quick and cocise. Exactly what I needed when I am frantically looking to finish a project and I want the next best thing to contants. (pseudo-comments)
    Much thanks.
  • Casey
    @Angela: Haha, you suck! Read up before you post...
  • Angela
    Seems the author may be unaware of const.

    More info: http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide:Constants

    Hope this helps!
  • Dan
    @Aaron : Thanks for such a detailed comment. I'll try your techniques and will make a post on them. You got it right, you were filtered as spam by Akismet! ;)

    @jon : As Aaron, you did a great job. I'll try it and write about it...

    Thanks to both of you!
  • Jon
    Firefox will let you define constants in several ways, but you can at least protect your constants.
    The following should work in IE, but I don't have a copy around to test with:

    function defineConstant( classType, constName, value ) {

    if( classType.prototype.__defineGetter__ != undefined ) {
    function get() {
    return value;
    }
    // Firefox lets us make real constants!
    classType.prototype.__defineGetter__( constName, get );
    classType.prototype.__defineSetter__( constName, function() {} );
    } else {

    if( classType.prototype._consts == undefined ) {
    classType.prototype._consts = new Array();
    }
    classType.prototype._consts.push( function() {
    this.watch( constName, function( property, oldValue, newValue ) {
    alert("Attempting to change value of constant property: " + property + " to value: " + newValue );
    throw new Error( "Attempting to change value of constant property: " + property + " to value: " + newValue );
    });
    });
    classType.prototype[constName] = value;
    if( classType.prototype._createConsts == undefined ) {
    classType.prototype._createConsts = function() {
    if( this._consts == undefined ) {
    return;
    }
    for( var x = 0; x < this._consts.length; x++ ) {
    this._consts[x].call( this );
    }
    };
    }
    }
    }

    Object.prototype._createConsts = function() {
    if( this._consts == undefined ) {
    return;
    }
    alert("Defining constants");

    for( var x = 0; x < this._consts.length; x++ ) {
    this._consts[x].call( this );
    }
    }

    function myClass() {
    this.NON_CONST_ID=42;
    this._createConsts();

    }

    defineConstant( myClass, "CONST_ID", 42 );
    defineConstant( myClass, "ANOTHER_CONST", 42 );
  • Aaron Faanes
    A way to solve this would be through closures. A closure is when a function is defined within another function, the variables that existed in the parent are accessible to the child. For example:

    function foo() {
    var blah = 2;
    return function bar() { return blah; }
    }
    var x = foo();
    alert(x() === 2); // You could also use console.log(x() === 2); here if you're sane and using firefox.

    This is initially very confusing, but understanding it allows many things that would be difficult in other languages, to be very easy here. I'll first hit the immediate example:

    function TheClass() {
    var CONST_VALUE = 42;
    this.CONST_VALUE = function() { return CONST_VALUE; }
    }

    Through a closure, we're able to get what you're looking for - a constant value. The compromise is now we have to call it, and we're creating it every time the class is instantiated. For a number, this cost is minimal, and I figure if one needs constness, he'll be willing to drop in a () here and there.

    We could (for purely rambling- and academic purposes) extend this example, so that we don't want it to be const, but just private.

    function TheClass() {
    var private_foo = 42;
    this.get_foo() { return private_foo; }
    this.set_foo(foo) { private_foo = foo; }
    }

    So now, we can ensure that foo is only changed from our accessor methods. Since it's made per class, we're also guaranteed that it's unique to each instance.

    A static constant value can also be achieved, albeit not as elegantly. The code would look something like this:

    function TheClass() {
    // ...
    }

    (function() {
    var const_value = 42;
    TheClass.const_value = function() { return const_value; }
    })();

    Once again, we're able to, through closures, have a true constant value. We could have had this in the global space, but that is evil, and also removes our guarantee since our const_value would be accessible globally, so an anonymous function that's immediately called does the trick.

    This isn't nearly as clear as it could be with a "const" keyword, but Javascript tends to side with flexibility in these matters.

    As far as an enum goes, I've worked it out a bit. Usually, I use an enum so that they can be easily switched:

    switch(this.size) {
    case Sizes.BIG:
    // ...
    case Sizes.MEDIUM:
    // ...
    }

    You can, however, use strings in switches (Something that I up till recently never considered trying), alleviating the ugliness of a chain of if...elses:
    switch(this.size) {
    case "big":
    // ...
    case "medium":
    // ...
    }

    This means that if you're concerned about enums changing, then this drops literals where there should be constants, potentially causing problems. In the end, there's not a very good, elegant way of doing a large number of these hacks to get familiar behavior. It's however, not too hard to wrap this stuff in a few small functions:

    function constant(value) {
    return function() { return value; }
    }

    Such that you could do:

    function TheClass() {
    this.const_value = constant(42);
    }

    Which is definitely prettier. Also works for our private, static stuff.

    TheClass.const_value = constant(42);

    Similarly, a quick enum function removes the common bug of 1,2,3,5:

    function enumerate(values) {
    var obj = {};
    for(var i in values) obj[values[i]] = parseInt(i);
    return obj;
    }
    enumerate("small medium large".split(" ")); // I'm lazy and dont like ["", "", "", "",""]

    Which is just a quick reverse of the keys to values.

    One danger here is omitting parseInt. for(var i in obj) makes i be the name of the key, and since Javascript converts all keys to strings, i will be "0". If you end up using === (which you should, since it's a little faster and alleviates some bugs with type coercion), then this will cause unexpected failures (As 0 !== "0" but "0" == 0. Go figure.)

    One thing that I've heard discouraged is the use of capitals to signify constants. Since a malicious, or really confused, programmer could change the function definition of our class, it's still not flawlessly constant. And on top of that, as someone pointed out, it's not constant if you have it in the class itself as a value, and CONSTANT() makes it look like it's a constant function, which, while true, seems redundant if you're hailing from a language not as free as Javascript. But this is mostly a philosophical issue of what feels right and comfortable.

    I hope this helps and isn't filtered as spam :)

    - Aaron
  • Dan
    @Joshua, I do not fully understand what you mean. Could you give me an example? I could add it to this article.

    @wkempf, I know that none of these are constants. I said so in my article.

    And for the "const" statement, I knew but the problem is that Internet Explorer (IE) doesn't support it. More on that subject on http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Statements:const
  • wkempf
    Not accurate. First, none of your examples are constants. Every single one of the examples can be modified at runtime with no error. Second, JavaScript does have constants: http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide:Constants.
  • Joshua E Cook
    Why not take it a step farther and use classes and objects as constant values? This still doesn't prevent a programmer from changing the value of the constant, but it does offer the flexibility of polymorphism.
  • Dan
    Frank, it's not ":" character that does something but the structure

    {
    key1 : value1,
    key2 : value2,
    keyN : valueN
    }

    This structure creates an anonymous object that can emulate an enum. If you want to know more, take a look at this article : http://www.javascriptkata.com/2007/03/22/how-to-do-enumerations-enum-in-javascript/
  • Frank
    That's a great article. What is the meaning of the ":" character in javascript? I would have thought of using the "=" sign instead of ":" in your enum declaration.
blog comments powered by Disqus