JavaScript ES6:如何迭代具有[Symbol()]名称的对象

3

我正在尝试找出如何迭代一个使用Symbol名称唯一标识属性的对象。例如,如果我有这个对象:

   const bowl1 = {
     'apple': { color: 'red', weight: 136.078 },
     'banana': { color: 'yellow', weight: 183.151 },
     'orange': { color: 'orange', weight: 170.097 },
     'peach': { color: 'yellow', weight: 176.845 }
   };

   for (var fruit in bowl1) {
       var item = bowl1[fruit];
       console.log(`${fruit}: `, item);
   }

   OUTPUT:
   apple:  { color: 'red', weight: 136.078 }
   banana:  { color: 'yellow', weight: 183.151 }
   orange:  { color: 'orange', weight: 170.097 }
   peach:  { color: 'yellow', weight: 176.845 }

   // can even write your own iterator to get the same results
   function* iterate_object(o) {
      var keys = Object.keys(o);
      for (var i = 0; i < keys.length; i++) {
         yield [keys[i], o[keys[i]]];
      }
   }

   // output is the same as above
   for (var [key, val] of iterate_object(bowl1)) {
      console.log(key, val);
   }

然而,如果我将此对象更改为使用符号作为以下方式:
   const bowl = {
     [Symbol('apple')]: { color: 'red', weight: 136.078 },
     [Symbol('banana')]: { color: 'yellow', weight: 183.15 },
     [Symbol('orange')]: { color: 'orange', weight: 170.097 },
     [Symbol('banana')]: { color: 'yellow', weight: 176.845 }
   };

请注意,符号被用于防止第二个香蕉覆盖第一个。
无论如何,以上使用的方法都不能正确迭代此对象。
是否有一种使用符号名称迭代对象的方法? 它需要被创建为一个类并具有一个迭代器方法吗?
提前感谢您的帮助。

在对象中使用“second banana”看起来像是对对象的误用。最好使用对象数组来避免对象属性混淆。 - Kosh
也许,这个例子是为了说明符号名称的使用而来的,因此可能并不代表它们的最佳使用方式。我正在尝试弄清如何迭代使用符号名称的对象。 - user2878805
如果您只是想知道如何使用符号迭代对象,则文档中已经提供了相应的示例:Symbols Examples。该示例还提到了在其中使用getOwnPropertySymbols的情况,即Object.getOwnPropertyNames()不会返回符号对象属性,但是您可以使用Object.getOwnPropertySymbols()来获取这些属性。 - Nope
实际上,您是在迭代对象键的数组,而不是对象本身。更有趣的问题是,您会得到哪个“香蕉”。 - Kosh
4个回答

9

无法获取符号属性名称,因为它们不被存储为典型的字符/字符串值,但您可以迭代由Object.getOwnPropertySymbols返回的列表,并使用它们从对象中提取信息。

const bowl = {
     [Symbol('apple')]: { color: 'red', weight: 136.078 },
     [Symbol('banana')]: { color: 'yellow', weight: 183.15 },
     [Symbol('orange')]: { color: 'orange', weight: 170.097 },
     [Symbol('banana')]: { color: 'yellow', weight: 176.845 }
   };
   
for(let sym of Object.getOwnPropertySymbols(bowl) ) {
   console.log(bowl[sym]);
}


1
如上所述,您无法获取符号属性名称,因为它们不以典型的字符字符串存储。然而,MDN网站确实说“此外,Object.getOwnPropertyNames()不会返回符号对象属性,但是,您可以使用Object.getOwnPropertySymbols()来获取这些属性。”
因此,为了获取关于对象的信息,请使用Object.getOwnPropertySymbols:
for(let sym of Object.getOwnPropertySymbols(bowl) ) {
    console.log(sym, bowl[sym]);
   }

输出:
   Symbol(apple) { color: 'red', weight: 136.18 }
   Symbol(banana) { color: 'yellow', weight: 183.15 }
   Symbol(orange) { color: 'orange', weight: 170.97 }
   Symbol(banana) { color: 'yellow', weight: 176.84 }

正如您所看到的,您无法获得符号名称作为字符串,但它将返回符号及其引用的对象。
如果您想将符号转换为字符串并只查看属性名称,则需要做一些额外的工作。
for(let sym of Object.getOwnPropertySymbols(bowl) ) {
      // remove the 'Symbol (' from string
      let symStr = String(sym).substring(7);

      // now lop off the last char ')'
      symStr = symStr.slice(0, -1);

      console.log(symStr, bowl[sym]);
   }

输出:
   apple { color: 'red', weight: 136.18 }
   banana { color: 'yellow', weight: 183.15 }
   orange { color: 'orange', weight: 170.97 }
   banana { color: 'yellow', weight: 176.84 }

如果您愿意,可以在一行上组合字符串函数。

let symStr = String(sym).substring(7).slice(0, -1);

也许Symbol并不是最好的用法,全局和局部符号都有。上面使用的示例和本课程材料中的示例都是局部的。

1

实际上有两种方法,会为您提供参考:

const bowl = {
[Symbol('apple')]: { color: 'red', weight: 136.078 },
[Symbol('banana')]: { color: 'yellow', weight: 183.151 },
[Symbol('orange')]: { color: 'orange', weight: 170.097 },
[Symbol('banana')]: { color: 'yellow', weight: 176.845 }
};

const bowlReflect = Reflect.ownKeys(bowl);
const ownPropertySymbols = Object.getOwnPropertySymbols(bowl);

**Method:1**
for(const fruit of bowlReflect){
 console.log(bowl[fruit])
 }

Method:2
for(const fruit of ownPropertySymbols){
 console.log(bowl[fruit])
}

0

const fantasma = Symbol('fantasma');
console.log(fantasma);
// Symbol(fantasma)

const objetoLiteral = {
// propiedad: valor,
  [fantasma]: '', // Symbol()
  uno: 1,
  dos: 2,
  tres: 3,
};
console.log(objetoLiteral);
/*
{
  uno: 1,
  dos: 2,
  tres: 3,
  [Symbol(fantasma)]: ''
}
*/

Object.getOwnPropertySymbols(objetoLiteral).map((propiedad) => {
  const valor = objetoLiteral[propiedad];
  console.log(propiedad, '➜', valor);
});
// Symbol(fantasma) ➜ 


当对一个已经有几年前被接受的答案提出可能的新解决方案时,提供更多背景信息会更有帮助。此外,如果您能够解释您的答案,它是如何工作的,为什么像它现在这样工作,以及其他答案没有做到的它所做的事情,那将会非常有帮助。 - L00_Cyph3r

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