38

I'm looking to create an associative array in JavaScript, but use constants defined as part of the class as indices.

The reason I want this is so that users of the class can use the constants (which define events) to trigger actions.

Some code to illustrate:

STATE_NORMAL = 0;
STATE_NEW_TASK_ADDED = 0;
this.curr_state = STATE_NEW_TASK_ADDED;

this.state_machine = {
    /* Prototype:
    STATE_NAME: {
        EVENT_NAME: {
            "next_state": new_state_name,
            "action": func
        }
    }
    */

    STATE_NEW_TASK_ADDED : { // I'd like this to be a constant
        this.EVENT_NEW_TASK_ADDED_AJAX : {
            "next_state": STATE_NEW_TASK_ADDED,
            "action" : function() {console.log("new task added");},
        }
    }
}

// Public data members.
// These define the various events that can happen.
this.EVENT_NEW_TASK_ADDED_AJAX = 0;
this.EVENT_NEW_TASK_ADDED_AJAX = 1;

I'm having trouble getting this to work. I'm not too great with JavaScript, but it looks like no matter what I do, the array gets defined with strings and not constants. Is there a way to force the array to use the constants?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Edan Maor
  • 9,772
  • 17
  • 62
  • 92

3 Answers3

64

In ECMAScript 6 you can use computed values for object keys:

var CONSTANT_A = 0, CONSTANT_B = 1
var state_machine = {
    [CONSTANT_A]: function () {
        return 'a'
    },
    [CONSTANT_B]: function () {
        return 'b'
    }
};

console.log(state_machine)

This does not work in Internet Explorer 11 nor in Safari browsers: https://kangax.github.io/compat-table/es6/#test-object_literal_extensions_computed_properties

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Kristian
  • 1,058
  • 1
  • 11
  • 16
44

See Kristian's answer re: ECMAScript 6/modern JavaScript, which has new syntax to make this possible.

The below is my original answer, from the pre-modern age.


The problem here, actually, is that you can't use a value for the key part when you're defining an object literally.

That is to say, this uses the constant values as expected:

var CONSTANT_A = 0, CONSTANT_B = 1;
var state_machine = {};
state_machine[CONSTANT_A] = "A";
state_machine[CONSTANT_B] = "B";
console.log(state_machine[0]); // => A
console.log(state_machine[1]); // => B

But this won't work as expected, instead using the string CONSTANT_A as key:

var CONSTANT_A = 0, CONSTANT_B = 1;
var state_machine = {
    CONSTANT_A: "A",
    CONSTANT_B: "B",
};
console.log(state_machine[0]); // => undefined
console.log(state_machine["CONSTANT_A"]); // => A
console.log(state_machine.CONSTANT_A); // => A

JavaScript has a shorthand to define object literals where you can omit the double-quotes around keys. Expressions can't be used, so CONSTANT_A won't be evaluated.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Asherah
  • 18,948
  • 5
  • 53
  • 72
20

Let's say you have the following constants:

const COMPANIES = "companies";
const BRANCHES = "branches";
const QUEUES = "queues";
const LOGOUT = "logout";

If you declare the dictionary this way:

var itemsToState = {
  COMPANIES: true,
  BRANCHES: false,
  QUEUES: false,
  LOGOUT: false,
}

// You will get:
// { COMPANIES: true, BRANCHES: false, QUEUES: false, LOGOUT: false }

Note the keys are uppercase ^ because it is not using the constant's value.

If you want to use the constant's value as key, you need to do this:

var itemsToState = {
  [COMPANIES]: true,
  [BRANCHES]: false,
  [QUEUES]: false,
  [LOGOUT]: false,
}

// You will get:
// { companies: true, branches: false, queues: false, logout: false }

Note the keys are lowercase ^ because it is using the constant's value.

Julian Espinel
  • 2,586
  • 5
  • 26
  • 20