16

I have an object fetched from 3rd party API as shown below:

{
    name:"Luke Skywalker",
    __typename:"People",
    Symbol(id):"ROOT_QUERY.people."
}

While "Luke Skywalker" can be accessed by simply object.name, how can I get access to the value of Symbol(id) property of this object?

Bakhtiiar Muzakparov
  • 1,683
  • 11
  • 21
  • You mean `objectVariable['Symbol(id)']`? Looks quite strange to me. Or maybe `objectVariable.Symbol(id)`? – tilz0R Jun 24 '17 at 07:43
  • I tried it, but it is not working probably **Symbol** has a special meaning in javascript – Bakhtiiar Muzakparov Jun 24 '17 at 07:45
  • It's hard to answer the question the way it is now. What you've shown is an invalid object initializer, so we have to guess at how the object is actually created. But there are several ways to create that, depending on what `id` is, and they markedly affect the answer to the question. Yury's answer is one way, but note that if that Symbol is globally-registered, another way would involve `Symbol.for`. So we just need more information. – T.J. Crowder Jun 24 '17 at 07:53
  • @T.J.Crowder this is response object fetched from API, I think I can't check how object was initialized, the values are just copied from chrome console. – Bakhtiiar Muzakparov Jun 24 '17 at 07:57
  • @BakhtiiarMuzakparov: Well, again, how that Symbol is created matters. Chrome's console will show the Symbol the same way regardless of whether it was `Symbol("id")` or `Symbol.for("id")` that created it. See my answer for details. – T.J. Crowder Jun 24 '17 at 08:04
  • Keep in mind that if that API doesn't publicly expose that Symbol somewhere, it's probably not part of their public API, meaning you shouldn't access it since it could break in the future. If they do expose it, just use the symbol they've exposed. – loganfsmyth Jun 24 '17 at 18:09

4 Answers4

30

That object initializer is invalid, so it's hard to answer.

If that really is a Symbol-named property, the answer depends on whether the Symbol is globally-registered.

If it isn't, you can only discover the symbol via getOwnPropertySymbols. If it's the only one, great, you're in good shape:

var data = {
    name:"Luke Skywalker",
    __typename:"People",
    [Symbol("id")]:"ROOT_QUERY.people."
};
console.log(data[Object.getOwnPropertySymbols(data)[0]]);

That assumes that there's only one Symbol-named property, which we probably shouldn't do. Instead, let's look for the Symbol with the descriptive string "Symbol(id)":

var data = {
    name:"Luke Skywalker",
    __typename:"People",
    [Symbol("id")]:"ROOT_QUERY.people."
};
var sym = Object.getOwnPropertySymbols(data).find(function(s) {
  return String(s) === "Symbol(id)";
});
console.log(sym ? data[sym] : "Symbol(id) not found");

But if it's globally-registered and you know what string it's registered under, you can use Symbol.for to get it:

var data = {
    name:"Luke Skywalker",
    __typename:"People",
    [Symbol.for("id")]:"ROOT_QUERY.people."
};
console.log(data[Symbol.for("id")]);
T.J. Crowder
  • 879,024
  • 165
  • 1,615
  • 1,639
  • marking you as an answer. First option has worked, so I believe symbol was not globally registered then. Thanks! – Bakhtiiar Muzakparov Jun 24 '17 at 08:11
  • @BakhtiiarMuzakparov: If the second one doesn't work, yeah, it would mean that it's not globally-registered under the string `"id"`. Just beware that if they add other Symbols to that object as the API is upgraded, you'll need to be careful to get the right one. I've added a (new) second code block above to help you ensure you get the right one. – T.J. Crowder Jun 24 '17 at 08:14
  • Kind of ridiculous that the official documentation doesn't even show this: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertySymbols – AndroidDev Jul 20 '20 at 16:29
  • @AndroidDev - MDN isn't "official documentation," it's Mozilla's community-driven documentation site. :-) The only official documentation is [the spec](https://tc39.es/ecma262/). MDN is written by and for programmers all over the world. In general, it's very, very good, but there is the odd gap here and there -- which anyone can fix. :-) What's the bit that's missing though...? [This](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol) seems to at least minimally cover the above... – T.J. Crowder Jul 20 '20 at 16:31
3

You can use Object.getOwnPropertySymbols() to retrieve it, but this would retrieve all symbols tied to an object. If you want to get that particular symbol on the object directly, you need to store that Symbol object else to be re-used.

const sym = Symbol(id);
const example = {
  name:"Luke Skywalker",
  __typename:"People",
  [sym]:"ROOT_QUERY.people."
}

console.log(example[sym]) //Equals "ROOT_QUERY.people."
Nick Wyman
  • 1,070
  • 11
  • 18
  • The OP's said (in a comment) that they're getting this object from an API, so they're not going to have the Symbol (other than retrieving it from the object, or if it's globally-registered). – T.J. Crowder Jun 24 '17 at 08:07
2

Symbols were designed to define unique property names to avoid collisions. So you should either have access to the symbol used to construct the object or get all symbols using getOwnPropertySymbols

const obj = {
  [Symbol('id')]: 1
}

console.log(obj[Symbol('id')])

const symbols = Object.getOwnPropertySymbols(obj)

console.log(obj[symbols[0]])
Yury Tarabanko
  • 39,619
  • 8
  • 73
  • 90
2

Adding to @T.J. Crowder, Symbols can also be discovered through Reflect.ownKeys which will list all object own keys: property names & symbols.

const data = {
    name:"Luke Skywalker",
    __typename:"People",
    [Symbol("id")]:"ROOT_QUERY.people."
};

const sym = Reflect.ownKeys(data).find(s => {
  return String(s) === "Symbol(id)";
});
console.log(sym ? data[sym] : "Symbol(id) not found");
Marcos Casagrande
  • 29,440
  • 5
  • 62
  • 77