JavaScriptには、いくつもプロパティ列挙の方法があります。ただ、原則と歴史的な経緯を踏まえれば、どれが何を返すかは比較的わかりやすく整理できます。
TL; DR(今北産業)
- プロトタイプをたどるのは演算子だけ
-
ownの付くメソッドはenumerableを見ない -
enumerableを見るものはSymbolを通さない
ただし、Reflectにあるメソッドの中には一部例外も存在します。
Symbolの歴史的経緯
まずはそれぞれの手法が何を返すのかピックアップする前に、Symbolについて掘り下げておきます。
SymbolはES6から導入された、「プロパティのキーとして使える特殊な値」ですが、これはSymbol.iteratorのような特殊メソッドを、既存のJavaScriptの動作に影響しないように導入するために作られました。
そのため、ES5に存在したfor-in、Object.keysなどではSymbolは扱わないようになっています(in演算子やhasOwnPropertyにシンボルを与えることはES5では不可能ですので、これらはシンボルで呼んでも正常動作しますが、互換性に影響はありません)。また、Symbolをキーにしたプロパティについて、enumerableによって動作を変えるものもありません。
各手法について
for-in
for-inは、プロトタイプまでさかのぼって、enumerableな文字列キーのプロパティをリストアップしていきます。
Object.keys、Object.values、Object.entries
Object.keysでは、自分自身にあるenumerableな文字列キーのプロパティを詰めた配列を返します。
Object.valuesやObject.entriesはES6以降で入ったものですが、ピックアップするキーの基準はObject.keysと同じです。
Object.getOwnPropertyNames
Object.getOwnPropertyNamesでは、自分自身にある(enumerableでないものも含めた)文字列キーのプロパティを詰めた配列を返します。Symbolは入りません。
Object.getOwnPropertySymbols
Object.getOwnPropertySymbolsは名前の通り、自分自身にあるSymbolのキーの一覧を返します。enumerableは影響しません。
Reflect.ownKeys
Reflect.ownKeysはObject.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target)) と同じ値、つまり自身にあるプロパティすべて(文字列のあとにSymbol)を返します。
その他
プロパティの順序は、どの手法をとっても表示されるものについては一貫していますが、どのような順序になるかは規定されていません。また、プロトタイプが存在するオブジェクトで、プロトタイプと違うenumerableを設定するとわけのわからないことになることもありますので、要注意です。
外部リンク
-
Enumerability and ownership of properties - MDN(日本語版には
Symbolへの言及がありませんでした)