In Javascript, an object is a set of several key/value pairs, separated by the two points (i.e., chave : valor
).
About the keys
The key can be a string:
// a chave é uma string (está entre aspas)
let x = { 'chave' : 'valor' };
console.log(x); // { "chave": "valor" }
But it can also be used a number, that the object is created without any problem:
// a chave é um número (está sem aspas)
let x = { 1 : 'valor' };
// mas ao imprimir, vemos que a chave está entre aspas
console.log(x); // { "1": "valor" }
// isso acontece porque ela foi convertida para string
console.log(Object.keys(x)); // [ "1" ]
console.log(typeof(Object.keys(x)[0])); // string
Note that the object is created using the number as key (the 1
is without quotes). But when printing the object, it appears in quotes ("1"
). This is because when a number is used as a key, it is converted to string. According to the documentation:
Any non-string Object, including a number, is typecasted into a string via the toString method.
That is, implicitly is called the method toString()
which converts number to string.
So in fact, there is nothing wrong with the keys of your object, from the syntactic point of view (there is perhaps a more semantic/conceptual problem, but we’ll get there).
The only point - which may be inconvenient - is what the @Wictor Chaves mentioned: how to access these properties. While a key string can be accessed as x.chave
, with numeric keys this is not possible (x.1
syntax error), and the only way is to use the brackets:
let x = { 1: 'abc', 'chave': 'def' };
console.log(x.chave); // def
// console.log(x.1); // erro de sintaxe
// assim funciona
console.log(x[1]); // abc
console.log(x['1']); // abc
console.log(x['chave']); // def
Notice what to call x[1]
(with the 1
unquote) works as it is also converted to string (so it is the same as x['1']
).
About the values
As for the values, they can be of any kind: number, string, boolean, array, and even another object. I mean, if I have this:
let x = {
1: {
id: 1,
name: 'Planet Earth',
}
};
console.log(x); // { "1": { "id": 1, "name": "Planet Earth" } }
// a chave "1" contém um objeto
console.log(x[1]); // { "id": 1, "name": "Planet Earth" }
console.log(typeof(x[1])); // object
Note that in 1 : { "id": 1, "name" : "Planet Earth" }
, the 1
is a key, and its value is another object ({ "id": 1, "name" : "Planet Earth" }
).
That is, the object x
contains the key 1
, whose value is another object (which in turn holds the keys id
- the value of which is a number - and name
- whose value is a string).
Again, from a syntactical point of view, nothing wrong here. We are only defining that one of the keys has as value another object, this is perfectly normal.
About your object itself
What might be odd is the specific shape of this object, and the fact that these numbers seem redundant. At least in the given example, the value of the key is the same as in the respective id
, then perhaps it would be better to simply have an array of objects (as suggested by reply from @emilioheinz):
// array com 3 filmes (delimitado por [ ])
const movies = [
{
id: 1,
name: 'Planet Earth',
},
{
id: 2,
name: 'Selma',
},
{
id: 3,
name: 'Million Dollar Baby',
}
];
console.log(movies);
// imprimir id e name do primeiro filme
console.log(movies[0].id); // 1
console.log(movies[0].name); // "Planet Earth"
// imprimir nome e id de todos os filmes
movies.forEach(filme => console.log(filme.id, filme.name));
Notice that the delimiters became [
and ]
, for now movies
is a array, each element being an object (which in turn has the keys id
and name
). And since we now have an array, we don’t need to put the keys, only the values.
The difference is that arrays start with zero index, then the first element (the film with id
1) will be movies[0]
, the second will be movies[1]
and so on.
But if you’re getting the object movies
in the given format, you can travel it smoothly:
const movies = {
1: {
id: 1,
name: 'Planet Earth',
},
2: {
id: 2,
name: 'Selma',
},
3: {
id: 3,
name: 'Million Dollar Baby',
}
};
// imprime a chave e o nome do respectivo filme
Object.keys(movies).forEach(chave => console.log(chave, movies[chave].name));
// ou esqueça a chave (já que é igual ao id) e use somente os valores
Object.values(movies).forEach(filme => console.log(filme.id, filme.name));
But I still find it kind of "weird" to have the information in this format, because for me it seems better to have an array of movies, rather than an object whose keys are the ID’s of those movies. Read on in this question, who has an interesting discussion about a case similar to yours.
Bonus
Just as a curiosity, when the documentation says that any object is converted to string when used as key, is any same object:
let x = {};
// usar função como chave
x[function() { }] = 'function';
// usar regex como chave
x[/.+/] = 'regex';
// a function e a regex são convertidas para string
console.log(x); // { "function() { }": "function", "/.+/": "regex" }
The only restriction is that you can’t use the function
and regex directly (doing something like x = { /.+/ : 'regex'}
, because it gives syntax error). But using the brackets, it is perfectly possible, as strange as it may seem. But it is not at all useless, there’s always someone who finds some use for such things.
Sensational! [+1], I even wanted to create a question about the bonus, so you can talk more about the theme.
– Wictor Chaves
@I think that would be an interesting question. Just do not know how much I would contribute, since it is a feature that I do not use much, but anyway, I think valid, because doing a quick search, I did not find any specific question about it here on the site...
– hkotsubo