Is there any way to use a numeric type as an object key?
Asked Answered
D

12

167

It seems that when I use a numeric type as a key name in an object, it always gets converted to a string. Is there anyway to actually get it to store as a numeric? The normal typecasting does not seem to work.

Example:

var userId = 1;
console.log( typeof userId ); // number
myObject[userId] = 'a value';
console.dir(myObject);

Dir Output:

{
    '1': 'a value'
}

What I want is this:

{
    1: 'a value'
}

Advice?

Dysphagia answered 3/9, 2010 at 5:58 Comment(2)
Also see this comment - #3633862Matthia
I tried your example, but I got the result you want. Can you clarify?Paresthesia
A
200

No, this is not possible. The key will always be converted to a string. See Property Accessor docs

Property names must be strings. This means that non-string objects cannot be used as keys in the object. Any non-string object, including a number, is typecasted into a string via the toString method.

> var foo = {}
undefined

> foo[23213] = 'swag'
'swag'

> foo
{ '23213': 'swag' }

> typeof(Object.keys(foo)[0])
'string'
Azoic answered 3/9, 2010 at 6:4 Comment(18)
Thank you. Is this considered a flaw in the language, or is it accepted as a good design decision?Dysphagia
That's rather subjective. As William noted, for integer keys you can instead use an array. Most JS engines can use sparse arrays behind the scenes.Azoic
Even in an array, all property names are converted to strings.Bookman
@TimDown, that's very misleading. Array indexes and array properties are not the same thing.Roice
@Roamer-1888: Not, it isn't. The only difference is that assigning a numeric property to an array affects the array's length property.Bookman
@TimDown, nope that's certainly not the only difference. Javascript is not like PHP, which supports associative arrays. Javascript allows only (sparse) numeric array indexes. It also allows array properties/methods to be set/read, but they are NOT ARRAY ELEMEMTS!!!Roice
That the length property changes when array elements are added/removed, is symptomatic of the difference, not the difference itself.Roice
@Roamer-1888: I'm not clear on what you're saying. All I'm saying is that the only difference between getting and setting properties when using an Array and a plain Object is that setting a numeric property on an Array can affect the length property. There is no other distinction between a property with a numeric and non-numeric name (and as I've previously mentioned, a numeric property name is converted to a string when setting the property anyway).Bookman
@TimDown, and what I'm saying is that you are wrong. "Setting a numeric property on an Array can affect the length property" is an incorrect statement. Javascript Array properties are completely independent of Array elements. What confuses people is that associative syntax, eg myArray["1"] = foo, appears to be setting a property, whereas it actually sets an array element, but only because "1" is a string representation of an integer, which is complete linguistic nonsense - but that's Javascript.Roice
Meanwhile, if you were to execute myArray["myProperty"] = foo, an Array element would not be created - the property myProperty would be set on the Array, but independently of the Array elements and the length property would be unaffected. See demo. Please trust me. I may only have a rep of a few hundred here on SO, but I've been writing this stuff for close on two decades and Array basics haven't changed in that time.Roice
@Roamer-1888: Your demo doesn't disprove anything I've said, and even proves that "setting a numeric property on an Array can affect the length property". I suggest reading the ECMAScript spec: array elements are just properties with special behaviour when setting.Bookman
@Roamer-1888: I feel the same. We might have the same understanding and just be arguing about terminology, seeing as we're both so entrenched. It bothers me and I want to know what it is you think I'm wrong about, so if you want to continue then we could do so in chat.Bookman
@TimDown, too busy with a heap of other stuff. May not emerge for several days. Best wishes.Roice
@Roamer-1888: "Javascript Array properties are completely independent of Array elements" is an incorrect statement. myArray["1"] = foo doesn't just appear to be setting a property, it is in fact setting a property (with a key "1") in every sense of the definition of property. Eg, myArray.hasOwnProperty("1") yields true. Semantically, this property can also be considered an "element" by virtue of having a numeric key, but there is nothing further that distinguishes an array "element" from an array property. Read the spec. If you still disagree, kindly cite your source.Sevenup
@Hans, this is precisely why nobody in their right mind, yourself included I hope, would attempt either to teach or to learn javascript programming from the Ecmascript specification(s), which are concerned with implementation of the language, not it usage. It is true that an array's members are properties of an underlying (concrete) object, but they are members of the (conceptual) array - not properties. It is an unfortunate shortcoming of the language that some of the underlying implementation is exposed in some of the notations available to programmers.Roice
@Roamer-1888: I would rather people learned the reality of how the language works (which may well involve some reading of or reference to the spec) than one person's preconceived idea of some (actually non-existent) difference between array and object properties. It sounds like you're projecting ideas from another language onto JavaScript.Bookman
@TimDown Agreed. A nice feature of specs is that they allow people engaged in a technical discussion to sync up on terminology, avoiding time wasted arguing semantics.Sevenup
Please be noted that "The keys of an Object are Strings and Symbols; a symbol value may be used as an identifier for object properties" ReferenceStitching
T
50

In an object, no, but I have found Map extremely useful for this application. Here is where I have used it for numeric keys, a key-based event.

onKeydown(e) {
  const { toggleSidebar, next, previous } = this.props;

  const keyMapping = new Map([
    [ 83, toggleSidebar ],  // user presses the s button
    [ 37, next          ],  // user presses the right arrow
    [ 39, previous      ]   // user presses the left arrow
  ]);

  if (keyMapping.has(e.which)) {
    e.preventDefault();
    keyMapping.get(e.which)();
  }
}
Trey answered 31/5, 2016 at 16:46 Comment(1)
The 101 of elegant Ludumdare entries! +1Coccidioidomycosis
M
14

Appears to be by design in ECMA-262-5:

The Property Identifier type is used to associate a property name with a Property Descriptor. Values of the Property Identifier type are pairs of the form (name, descriptor), where name is a String and descriptor is a Property Descriptor value.

However, I don't see a definite specification for it in ECMA-262-3. Regardless, I wouldn't attempt to use non-strings as property names.

Modernism answered 3/9, 2010 at 7:8 Comment(0)
T
9

Here is the solution. Please tell me the environmental setups if this is not working

const screens = {
    "768": "large",
    "200": "small"
}

const keys = Object.keys(screens).map(key => parseInt(key))
                                         // OR Number(key)

console.log(keys) // Output [200, 768]
Tommyetommyrot answered 17/11, 2020 at 5:47 Comment(0)
M
8

you can use, Map if you want different datatype as keys

const map1 = new Map();

map1.set(1,3)
map1.set('1','string')

// expected output: 3

console.log(map1.get(1)) //output 3;
console.log(map1.get('1')) //output 'string';
Mcnally answered 14/3, 2022 at 4:45 Comment(0)
R
1

Do we need something like this?

var userId = 1;var myObject ={};
console.log( typeof userId ); // number
myObject[userId] = 'a value';
console.dir(myObject);

Console: Object

1 : "a value"

Roose answered 5/9, 2018 at 7:54 Comment(0)
S
0

You can't, but you can always convert keys to a numbers

const data = { 15: "value", name: "Apple" };

const result = Object.keys(data) // get keys as an array
    .map((item) => {
    return parseInt(item); // convert to integer number
    })
    .filter((item) => !isNaN(item)); // remove non number elements

    console.log(result); //Output: [15] 
Searching answered 8/8, 2022 at 12:39 Comment(0)
I
0
const a = {
    '1': 'a value'
}
//by using a + before any string value it will convert(parse) that into a number
const b = Object.key(a);
console.log(+b); //parse
console.log(typeof b); //number
Intersection answered 11/10, 2022 at 14:6 Comment(0)
I
0

According to ECMA-262 Edition 13 (as of 2024): A property key value is either an ECMAScript String value or a Symbol value'.

So the answer is still NO, at least not natively.

However, it is technically possible to hack it and convert 32-bit integers into 4-char sequences (strings) and use them as keys (note that those strings might not be 4-byte long). This approach might be useful for compression during transmission of large data objects. Example:

'use strict';

const { log } = console;

const data = [
    { t: 1705432979, s: 124, d:   0, pl: 0 },
    { t: 1705432992, s: 125, d:  17, pl: "004500" },
    { t: 1705433022, s: 124, d:   0, pl: 0 },
    { t: 1705433330, s:  19, d: 657, pl: "deadbeef" },
];
//log("data_orig:", data);

function int2bstr(val) {
    const arr_u32 = new Uint32Array(1);
    arr_u32[0] = val;
    const arr_u8 = new Uint8Array(arr_u32.buffer);
    return String.fromCharCode(...Array.from(arr_u8));
};
function bstr2int(str) {
    if (str.length !== 4) { throw "Invalid data"; };
    const arr_u8 = new Uint8Array(4);
    const arr_u32 = new Uint32Array(arr_u8.buffer);
    for (let i=0;i<4;++i) { arr_u8[i] = str.charCodeAt(i); };
    return arr_u32[0];
};
// Converting 'Array' into 'Object' and using converted value of property 't' as key.
const data_compr = data.reduce((acc, val) => {
    const k = int2bstr(val.t);
    acc[k] = structuredClone(val);
    delete acc[k].t;
    return acc;
}, {});
log("data_compr:", data_compr);
/*
data_compr: {
    // NOTE: each key is now a 4-char string
    "\u0093צe":{ s: 124, d:   0, pl: 0 },
    " צe":     { s: 125, d:  17, pl: "004500" },
    "¾×¦e":     { s: 124, d:   0, pl: 0 },
    "òئe":     { s:  19, d: 657, pl: "deadbeef" }
}
*/

const data_decompr = Object.entries(structuredClone(data_compr)).map(([k,val]) => {
    val.t = bstr2int(k);
    return val;
});
log("data_decompr:", data_decompr);
Iphagenia answered 15/2, 2024 at 18:19 Comment(0)
C
-1

Per Mozilla: Spread syntax

let obj1 = { foo: 'bar', x: 42 };
let obj2 = { foo: 'baz', y: 13 };
const merge = ( ...objects ) => ( { ...objects } );

let mergedObj1 = merge (obj1, obj2);
// Object { 0: { foo: 'bar', x: 42 }, 1: { foo: 'baz', y: 13 } }

let mergedObj2 = merge ({}, obj1, obj2);
// Object { 0: {}, 1: { foo: 'bar', x: 42 }, 2: { foo: 'baz', y: 13 } }

console.log(mergedObj1);
console.log(mergedObj2);

Just order the items before hand and you should get the result you want.

So for your case:

const merge = (...objects) => ({...objects});

// An object with numeric keys
const values = ["a value", "another value", "and another value"];
        
let merged = merge(...values);

console.log(merged);
Celebrated answered 8/1, 2021 at 23:15 Comment(2)
this doesn't answer at all the question and how you see those indexes are converted in String typePanta
Doing a shallow copy of an object just to convert keys to numbers seems like insane overkillDuaneduarchy
I
-2

You can try this:

arr = {}
function f(a,b,c) {
      arr = arguments
}
f("*","#","_")
console.log(arr)
//returns Object { 0: "*", 1: "#", 2: "_" }```
Ilsa answered 23/6, 2021 at 14:26 Comment(1)
Writing something like arr = {} is like writing myBool = 'blue'. It's almost maliciously unreadable when it comes to code maintenance and updates. A {} is not an array, it's an object. An array is written [] and calling a spade a shovel doesn't change that factDuaneduarchy
A
-4

In JavaScript, numerical strings and numbers are interchangeable, so

myObject[1] == myObject['1']

If you really want number to be the key for an object, you might want an array (i.e. created with new Array() or []).

Activity answered 3/9, 2010 at 6:2 Comment(2)
Thanks for the response but this is not entirely accurate. A numeric will only return as 'number' from a typeof, and vice versa with a string.Dysphagia
@william 'numerical strings and numbers are interchangeable' is simply not correct. Numbers are Numbers and Strings are Strings. See Object.prototype.toString.call(someObject) The issue is you can't use a Numbers as keys.Lampas

© 2022 - 2025 — McMap. All rights reserved.