Object property name as number

According to the official JavaScript documentation you can define object literal property names using integers:

Additionally, you can use a numeric or string literal for the name of a property.

Like so:

me = {
    name: "Robert Rocha",
    123: 26,
    origin: "Mexico"
}

My question is, how do you reference the property that has an integer as a name? I tried the usual me.123 but got an error. The only workaround that I can think of is using a for-in loop. Any suggestions?

Answers:

Answer

You can reference the object's properties as you would an array and use either me[123] or me["123"]

Answer

Dot notation only works with property names that are valid identifiers. An identifier must start with a letter, $, _ or unicode escape sequence. For all other property names, you must use bracket notation.

In an object literal, the property name must be an identifier name, string literal or numeric literal (which will be converted to a string since property names must be strings):

var obj = {1:1, foo:'foo', '+=+':'+=+'};

alert(obj[1] + ' ' + obj.foo + ' ' + obj['+=+']); // 1 foo +=+
Answer

You can use me[123] or me["123"]. Both work.

Answer

You can use bracket notation me[123].

Answer

Just in case anyone else was confused by this: using integer (rather than string) property names may give slightly different - though functionally the same - results (depending on the browser) when you have objects within objects.

Simple objects with no nested objects have consistent behavior across browsers (though as the accepted answer says, we need to use brackets instead of dots to access integer property names):

var str_simple = {
    a: "b", c: "d", e: "f", g: "h",
};
str_simple.a === "b"; // true
str_simple.e === "f"; // true

var int_simple = {
    1: 2, 3: 4, 5: 6, 7: 8,
};
int_simple[1] === 2; // true - must use brackets instead of dots
int_simple[5] === 6; // true
// this works b/c int property names are coerced to strings anyway
int_simple[1] === int_simple['1']; // true

And this nested object with string keys works exactly as expected:

var str_nested = {
    a: {b: "c"}, 
    d: {e: "f", g: "h"},
};
str_nested.a; // returns object as expected, no matter the browser - {b: "c"}
str_nested.a.b === "c"; // true
str_nested.d.g === "h"; // true

But this equivalent nested object with integer keys returns slightly different results depending on the browser, though you can still access the nested objects in the same way (so functionally, it still works the same):

var int_nested = {
    1: {2: 3}, 
    4: {5: 6, 7: 8},
};

// latest Chrome (57)
// Safari 10 (latest for my Mac, 10.10 Yosemite)
int_nested[1]; // returns object as expected - {2: 3}
int_nested[1][2] === 3; // true

// latest Firefox (52)
int_nested[1]; // RETURNS ARRAY-LIKE OBJECT - Object [ <2 empty slots>, 3 ]
int_nested.length; // undefined because it's not technically an array
int_nested[1][2] === 3; // true - works b/c object was padded with empty slots

// and again, in all browsers, we can exchange the integer keys
// for equivalent strings since property names are coerced to strings anyway
int_nested[1][2] === int_nested['1'][2];
int_nested['1'][2] === int_nested[1]['2'];
int_nested[1]['2'] === int_nested['1']['2'];

This behavior will still be slightly different but functionally the same if you programmatically construct a nested object. For example, say we wanted to write a function that would take a list of pairs (e.g. [[0, 0], [0, 1], [1, 2], [2, 3]]) and convert it into a nested object so we could check if the pair is in the object with O(1) time (e.g. {0: {0: true, 1: true}, 1: {2: true}, 2: {3, true}}). Note that Sets check reference equality and not value equality, so we couldn't store the pair itself in the Set and achieve the same results:

// [[0, 0], [0, 1], [1, 2], [2, 3]] ->
// {
//  0: {0: true, 1: true},
//  1: {2: true},
//  2: {3: true},
// }
function createNestedObject(pairs) {
    var obj = {};
    for (var pair of pairs) {
        var x = pair[0], y = pair[1];
        // must create outer object for each unique x or else
        // obj[x][y] would fail b/c obj[x] would be undefined
        if (!obj.hasOwnProperty(x)) {
            obj[x] = {};
        }
        obj[x][y] = true;
    }
    return obj;
}

function exists(nested, pair) {
    var x = pair[0], y = pair[1];
    // uses !! operator so if pair isn't in nested
    // we return false instead of undefined
    return !!(nested[x] && nested[x][y]);
}

Pairs with strings will work as expected:

var pairs = [["a", "a"], ["a", "b"], ["c", "d"], ["d", "e"]];
var nested = createNestedObject(pairs);
nested; // as expected - {a: {a: true, b: true}, c: {d: true}, d: {e: true}}
exists(nested, ["a", "a"]); // true
exists(nested, ["a", "b"]); // true
exists(nested, ["ZZZ", "ZZZ"]); // false

But in certain browsers, integer pairs will be different but functionally the same:

var pairs = [[0, 0], [0, 1], [1, 2], [2, 3]];
var nested = createNestedObject(pairs);
nested; // in Safari 10/Chrome 57 - returns nested objects as expected
nested; // in Firefox 52 - Object [ Object[2], Object[3], Object[4] ]
// BUT still gives correct results no matter the browser
exists(nested, [0, 0]); // true
exists(nested, [0, 1]); // true
exists(nested, ['0', '0']); // true
exists(nested, [999, 999]); // false
Answer

The situation with numeric property names seems more complicated than it is explained in the answers so far. It is true that you can access such properties via for-in loop. However, it might be important to know that for-in loop gives keys as strings, not as numbers as you might expect:

var obj = {1:2};
for (var key in obj) {
    alert(typeof(obj[key])); // you get "number" as expected, however
    alert(typeof(key)); // you get "string", not "number"
}

A similar thing happens during serialization with JSON:

JSON.stringify( {1:2} ) === '{"1":2}'

So if you code depends on this little detail you better be aware of it.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.