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
への言及がありませんでした)