45

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?

4 Answers 4

67

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

Sign up to request clarification or add additional context in comments.

1 Comment

Ah, ES6 is so great
45

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.

Comments

27

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.

1 Comment

The examples make the code and answer easy to understand. Thanks!
0

In some JS implementations, like Rhino using ES2015, you can't use the example provided by Julian Espinel, so this is an alternative that worked for me:

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

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

console.log(itemsToState);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.