访问对象上Symbol(id)属性的值

28

我从第三方API获取了一个对象,如下所示:

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

虽然可以通过简单的object.name访问"Luke Skywalker",但是我如何获取该对象的Symbol(id)属性的值?


你是指 objectVariable['Symbol(id)'] 吗?对我来说看起来很奇怪。或者也许是 objectVariable.Symbol(id) - ringbuffer_peek
1
我尝试了,但它似乎不起作用。在JavaScript中,Symbol具有特殊的含义。 - Bakhtiiar Muzakparov
现在这个问题很难回答。你展示的是一个无效的对象初始化器,所以我们必须猜测对象实际上是如何创建的。但是有几种不同的方式可以创建它,这取决于id是什么,而且它们显著地影响到问题的答案。Yury的回答是一种方式,但请注意,如果该符号是全局注册的,另一种方式将涉及Symbol.for。因此,我们需要更多信息。 - T.J. Crowder
@T.J.Crowder 这是从 API 获取的响应对象,我认为我无法检查对象如何初始化,这些值只是从 Chrome 控制台复制过来的。 - Bakhtiiar Muzakparov
@BakhtiiarMuzakparov:同样的,创建Symbol的方式很重要。无论是Symbol("id")还是Symbol.for("id")创建的,Chrome的控制台都会以相同的方式显示Symbol。有关详细信息,请参见我的答案。 - T.J. Crowder
请记住,如果该API没有在公共位置公开显示该符号,则该符号可能不是其公共API的一部分,这意味着您不应访问它,因为它可能会在未来发生变化。如果他们确实公开了它,请使用他们公开的符号。 - loganfsmyth
4个回答

52

那个对象初始化器是无效的,所以很难回答。

如果那真的是一个以Symbol命名的属性,答案取决于该Symbol是否全局注册。

如果没有被注册,你只能通过getOwnPropertySymbols发现该Symbol。如果它是唯一的,那太棒了,你就处于良好的状态:

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

假设只有一个名为Symbol的属性,这可能不太合适。相反,让我们寻找描述为"id"的Symbol:

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

需要注意的是,有多个符号具有相同的描述是完全有效的,因此上述代码再次使用它找到的第一个符号,但虽然这很奇怪,但可能会有多个符号:

const data = {
    name: "Luke Skywalker",
    __typename: "People",
    [Symbol("id")]: "Value for the first Symbol(id)",
    [Symbol("id")]: "Value for the second Symbol(id)",
};
const idSymbolKeys = Object.getOwnPropertySymbols(data).filter(
    (s) => s.description === "id"
);
console.log("'id' symbols found:", idSymbolKeys.length);
console.log(data[idSymbolKeys[0]]);
console.log(data[idSymbolKeys[1]]);

如果它是全局注册的,并且您知道它注册的字符串,就可以使用 Symbol.for 来获取它:

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


6
除了 @T.J. Crowder 提到的方法,Symbol 还可以通过 Reflect.ownKeys 发现,该方法将列出所有对象自有键:属性名和符号。

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");


3
你可以使用 Object.getOwnPropertySymbols() 方法来获取它,但这会检索与对象相关的所有符号。如果你想直接获取对象上的特定符号,你需要将该 Symbol 对象存储起来以便重用。
const sym = Symbol(id);
const example = {
  name:"Luke Skywalker",
  __typename:"People",
  [sym]:"ROOT_QUERY.people."
}

console.log(example[sym]) //Equals "ROOT_QUERY.people."

OP在评论中说他们从API获取此对象,因此除非从对象中检索它或全局注册,否则他们将无法获得该符号。 - T.J. Crowder

2

Symbols 的设计初衷是为了定义唯一的属性名称以避免冲突。因此,您应该要么访问用于构造对象的符号,要么使用getOwnPropertySymbols获取所有符号。

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

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

const symbols = Object.getOwnPropertySymbols(obj)

console.log(obj[symbols[0]])


是的,使用 Symbol.for 之后,冲突问题又出现了。 - user6445533

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接