78

According to the MDN 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?

Community
  • 1
  • 1
Robert
  • 10,126
  • 19
  • 78
  • 130
  • 3
    Try with `me[123]` as this another way of accessing unknown properties of objects as you can pass variables in. – Turnerj Jun 04 '13 at 01:36
  • Use [bracket notation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Member_Operators#Bracket_notation) - just as you would in the for-in-loop. You don't need to use a variable, you can pass an explicit value. – Bergi Jun 04 '13 at 01:47
  • Thanks for the edit Bergi. How do I embed links in text on stackoverflow? – Robert Jun 04 '13 at 03:07

6 Answers6

113

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

Tom
  • 4,422
  • 3
  • 24
  • 36
  • -1. There is no JSON string around. And it is no array, but a plain object. – Bergi Jun 04 '13 at 01:45
  • @Joshua I just tested it out in Chrome's console and it allows me to set and get object properties with or without the quotes. Same thing for arrays, they seem to work with either version too... – Tom Oct 15 '14 at 04:57
  • 2
    @Joshua - Your comment is wrong on all counts. Did you even try any of it? If `a` is an `Array`, you can assign `a[123] = 1` and then `a["123"] = 2` and the same array element will be changed. Likewise, if `o` is an `Object`, you can set `o[123] = 1` and it will set the `'123'` property of `o` (exactly as if you had executed `o['123'] = 1`. Further, since `Array` instances are also `Object` instances, you can set and read `a['xyz']` even if `a` is an `Array`. All of this behavior is described in the [ECMAScript Language Specification](http://www.ecma-international.org/ecma-262/5.1/). – Ted Hopp Nov 26 '14 at 00:07
  • 1
    FYI: most modern browsers optimise objects that only have integer keys (think dictionaries with integers as keys). So all else being equal `me[123]` is likely to be more performant. – Job Jun 29 '17 at 11:03
  • 1
    To explain that a bit further: I'm investigating `charAt` vs `charCodeAt` optimisations so the code below is a bit specific, but as you can see integer key lookup is _much_ faster (even calls to `hasOwnProperty` improve a bit, as well as `Map.get` calls). The caveat I found in earlier benchmarks is that you may _only_ have integer keys: http://jsbench.github.io/#f1f9afdba2eac615645c80335c48ed10 http://jsbench.github.io/#8345886c28796a6d825c292900d01777 – Job Jun 29 '17 at 11:19
  • Javascript syntax is nuts. If a field is named 123 it should be accessible as me.123 – Jason Cheng Apr 17 '19 at 20:23
  • @JasonCheng Then you run into other issues because a dot before a number could also indicate a decimal value. – kojow7 Dec 18 '20 at 03:28
29

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 +=+
RobG
  • 142,382
  • 31
  • 172
  • 209
16

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

Ted Hopp
  • 232,168
  • 48
  • 399
  • 521
7

You can use bracket notation me[123].

Steven Wexler
  • 16,589
  • 8
  • 53
  • 80
4

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
Community
  • 1
  • 1
Galen Long
  • 3,693
  • 1
  • 25
  • 37
4

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.