24

I'm using class members to hold constants. E.g.:

function Foo() {
}

Foo.CONSTANT1 = 1;
Foo.CONSTANT2 = 2;

This works fine, except that it seems a bit unorganized, with all the code that is specific to Foo laying around in global scope. So I thought about moving the constant declaration to inside the Foo() declaration, but then wouldn't that code execute everytime Foo is constructed?

I'm coming from Java where everything is enclosed in a class body, so I'm thinking JavaScript might have something similar to that or some work around that mimics it.

Scott Weldon
  • 9,673
  • 6
  • 48
  • 67
Tom Tucker
  • 11,676
  • 22
  • 89
  • 130

9 Answers9

31

All you're doing in your code is adding a property named CONSTANT with the value 1 to the Function object named Foo, then overwriting it immediately with the value 2.

I'm not too familiar with other languages, but I don't believe javascript is able to do what you seem to be attempting.

None of the properties you're adding to Foo will ever execute. They're just stored in that namespace.

Maybe you wanted to prototype some property onto Foo?

function Foo() {
}

Foo.prototype.CONSTANT1 = 1;
Foo.prototype.CONSTANT2 = 2;

Not quite what you're after though.

user113716
  • 318,772
  • 63
  • 451
  • 440
  • 1
    Fixed. I'm looking for a way to declare constants inside a block so that A) they are grouped together B) they run only once. – Tom Tucker Jan 25 '11 at 02:21
  • does putting it on the prototype gain you anything? – hvgotcodes Jan 25 '11 at 02:22
  • 1
    @Tom: I see. Yes, basically you're utilizing the `Foo` object as a namespace. That would work, but perhaps a better way is to add them to the `prototype` object. This is not constructed with each new instance. Rather it is a shared object among all instances of `Foo`. – user113716 Jan 25 '11 at 02:24
  • @hvgotcodes: Considering that they're intended to be constants, and presumably not overridden anywhere in the prototype inheritance chain, I'm not certain that it does. Perhaps a faster lookup from `this`, or perhaps not. – user113716 Jan 25 '11 at 02:29
  • @patrick dw Could you also elaborate on "None of the properties you're adding to Foo will ever execute"? My understanding is that - when the page is loaded, if the right hand side was say, string concatenation, the JS engine would execute the code and assign the result to the CONSTANT member. Maybe I got the concept wrong? – Tom Tucker Jan 25 '11 at 02:30
  • @patrick but if its a constant, wouldn't you reference it by Foo.CONSTANT1, not 'this'? Also, on Foo the property doesn't get initialized over and over either. I think the way he is doing it is fine... – hvgotcodes Jan 25 '11 at 02:32
  • @Tom: The right hand side will be evaluated only once, when the value is assigned to `CONSTANT1`. After that, it is just a property on an object, the same as it would be if you did: `var obj = {}; obj.CONSTANT1 = "value:" + someVariable;`. The result will be the concatenation of `"value:"` with the current value of `someVariable`. It won't change when new instances are created. – user113716 Jan 25 '11 at 02:34
  • 2
    @hvgotcodes: On the `prototype` it doesn't get initialized over and over either. Just once. If it is in the `prototype` object, you can reference it as `this.CONSTANT1`. You could also reference it directly if you wanted via `Foo.prototype.CONSTANT1`. If it is on `Foo` directly, then yes, it would be `Foo.CONSTANT1`. – user113716 Jan 25 '11 at 02:36
  • @hvgotcodes: ...I should clarify, that I mean within functions that are called from the context of `Foo`, you can use `this`. Also in the `constructor`. [Here's an example](http://jsfiddle.net/7NGqK/) of what I meant. `this.CONSTANT1` is accessed once in the constructor, and once in a method called from an instance. – user113716 Jan 25 '11 at 02:39
  • @patrick, yes I know. I just thought that the canonical way of declaring constants was on the constructor function or in a namespace, not on prototype. – hvgotcodes Jan 25 '11 at 02:44
  • @hvgotcodes: I think I missed the point of some of what you were saying in some of the comments. Yes, `Foo.CONSTANT1` is fine. I was confused by the original code in the question. If OP was just looking for a place to namespace some properties, then that approach works. – user113716 Jan 25 '11 at 02:49
  • @patrick, yeah, they are only constants. so we agree about if it is in fact a constant, they should go on the Constructor? I mean it doesn't really matter, but like I said, I thought the 'right' way to do constants was as I answered... – hvgotcodes Jan 25 '11 at 03:00
  • @hvgotcodes: Sorry, I just saw your last comment. It will come down to style but the constructor would be a convenient place to namespace them. – user113716 Jan 25 '11 at 04:23
14

You must make your constants like you said :

function Foo() {
}

Foo.CONSTANT1 = 1;
Foo.CONSTANT2 = 2;

And you access like that :

Foo.CONSTANT1;

or

anInstanceOfFoo.__proto__.constructor.CONSTANT1;

All other solutions alloc an other part of memory when you create an other object, so it's not a constant. You should not do that :

Foo.prototype.CONSTANT1 = 1;
Soap
  • 141
  • 1
  • 2
  • Note that __proto__ is not always available. Also, __proto__.constructor is not always what you think it is, esp. in case of multiple levels of inheritance, if the class author did not take special care to set it. You can simply use anInstanceOfFoo.CONSTANT1, and it will resolve nicely due to the proto-chain. – Nitzan Shaked Apr 16 '13 at 17:45
  • I combine them occasionally: `Foo.value = Foo.prototype.value = 42;` – superlukas Sep 01 '14 at 15:57
4

IF the constants are to be used inside of the object only:

function Foo() {
    var CONSTANT1 = 1,CONSTANT2 = 2;
}

If not, do it like this:

function Foo(){
    this.CONSTANT1=1;
    this.CONSTANT2=2;
}

It's much more readable and easier to work out what the function does.

3

First, I recommend moving your class declaration inside of an IIFE. This cleans up the code, making it more self-contained, and allows you to use local variables without polluting the global namespace. Your code becomes:

var Foo = (function() {
  function Foo() {
  }

  Foo.CONSTANT1 = 1;
  Foo.CONSTANT2 = 2;

  return Foo;
})();

The problem with assigning constants directly to the class as attributes is that those are writable. See this snippet:

var output = document.getElementById("output");

var Foo = (function() {
  function Foo() {
  }

  Foo.CONSTANT1 = 1;
  Foo.CONSTANT2 = 2;

  return Foo;
})();

Foo.CONSTANT1 = "I'm not very constant";

output.innerHTML = Foo.CONSTANT1;
<div id="output"></div>

The best solution I have found is to define read-only properties for accessing the constants outside of the class.

var output = document.getElementById("output");

var Foo = (function() {
  const CONSTANT1 = "I'm very constant";

  function Foo() {
  }

  Object.defineProperty(Foo, "CONSTANT1", {
    get: function() {
      return CONSTANT1;
    },
  });

  return Foo;
})();

Foo.CONSTANT1 = "some other value";

output.innerHTML = Foo.CONSTANT1;
<div id="output"></div>

(Technically you could ditch the const CONSTANT1 statement and just return the value from the property definition, but I prefer this because it makes it easier to see all the constants at a glance.)

Community
  • 1
  • 1
Scott Weldon
  • 9,673
  • 6
  • 48
  • 67
3

If you're using jQuery, you can use $.extend function to categorize everything.

var MyClass = $.extend(function() {
        $.extend(this, {
            parameter: 'param',
            func: function() {
                console.log(this.parameter);
            }
        });
        // some code to do at construction time
    }, {
        CONST: 'const'
    }
);
var a = new MyClass();
var b = new MyClass();
b.parameter = MyClass.CONST;
a.func();       // console: param
b.func();       // console: const
Marius Balčytis
  • 2,601
  • 20
  • 22
2

what you are doing is fine (assuming you realize that your example is just setting the same property twice); it is the equivalent of a static variable in Java (as close as you can get, at least without doing a lot of work). Also, its not entirely global, since its on the constructor function, it is effectively namespaced to your 'class'.

hvgotcodes
  • 118,147
  • 33
  • 203
  • 236
1

Also with namespaces

var Constants = {
    Const1: function () {
        Const1.prototype.CONSTANT1 = 1;
        Const1.prototype.CONSTANT2 = 2;
    },

    Const2: function () {
        Const2.prototype.CONSTANT3 = 4;
        Const2.prototype.CONSTANT4 = 3;
    }
};
Amc_rtty
  • 3,662
  • 11
  • 48
  • 73
  • 1
    Doesn't that mean you have to write Constants.Const1.CONSTANT1 to access it? – Tom Tucker Dec 15 '12 at 03:45
  • correct, that's the point, use this only if you wish to have all your constants grouped under a namespace - useful when you have a lot of Const functions and you like to keep them organized. – Amc_rtty Dec 15 '12 at 10:56
1

Your constants are just variables, and you won't know if you try and inadvertently overwrite them. Also note that Javascript lacks the notion of "class".

I'd suggest you create functions that return values that you need constant.

To get the taste of Javascript, find Javascript: the Good Parts and learn the idiomatic ways. Javascript is very different from Java.

9000
  • 39,899
  • 9
  • 66
  • 104
0

You said your coming from Java - why don't you store that class in 1 file then and constants at the end of the file. This is what I use:

filename: PopupWindow.js

function PopupWindow() {
    //private class memebers
    var popup, lightbox;
    //public class memeber or method (it is the same in JS if I am right)
    this.myfuncOrmyMemeber = function() {};
}

//static variable
PopupWindow._instance = null;
//same thing again with constant-like name (you can't have "final" in JS if I am right, so it is not immutable constant but its close enough ;) - just remember not to set varibales with BIG_LETTERS :D)
PopupWindow.MY_CONSTANT = 1;
//yea, and same thing with static methods again
PopupWindow._getInstance = function() {};

So only difference is the position of static stuff. It is not nicly aligned inside class curly braces, but who cares, its always ctrl+click in IDE (or I use ctr+l to show all class methods - IntellijIdea can do that in JS dunno how about other IDEs) so your not gonna search it by your eye ;)

Yea and I use _ before static method - it is not needed, I don't know why I started to do that :)

Srneczek
  • 2,143
  • 1
  • 22
  • 26