Edited at

JavaScriptのプロパティ列挙の3原則

JavaScriptには、いくつもプロパティ列挙の方法があります。ただ、原則と歴史的な経緯を踏まえれば、どれが何を返すかは比較的わかりやすく整理できます。


TL; DR(今北産業)


  • プロトタイプをたどるのは演算子だけ


  • ownの付くメソッドはenumerableを見ない


  • enumerableを見るものはSymbolを通さない

ただし、Reflectにあるメソッドの中には一部例外も存在します。


Symbolの歴史的経緯

まずはそれぞれの手法が何を返すのかピックアップする前に、Symbolについて掘り下げておきます。

SymbolはES6から導入された、「プロパティのキーとして使える特殊な値」ですが、これはSymbol.iteratorのような特殊メソッドを、既存のJavaScriptの動作に影響しないように導入するために作られました。

そのため、ES5に存在したfor-inObject.keysなどではSymbolは扱わないようになっています(in演算子やhasOwnPropertyにシンボルを与えることはES5では不可能ですので、これらはシンボルで呼んでも正常動作しますが、互換性に影響はありません)。また、Symbolをキーにしたプロパティについて、enumerableによって動作を変えるものもありません。


各手法について


for-in

for-inは、プロトタイプまでさかのぼってenumerableな文字列キーのプロパティをリストアップしていきます。


Object.keysObject.valuesObject.entries

Object.keysでは、自分自身にあるenumerableな文字列キーのプロパティを詰めた配列を返します。

Object.valuesObject.entriesはES6以降で入ったものですが、ピックアップするキーの基準はObject.keysと同じです。


Object.getOwnPropertyNames

Object.getOwnPropertyNamesでは、自分自身にある(enumerableでないものも含めた)文字列キーのプロパティを詰めた配列を返します。Symbolは入りません。


Object.getOwnPropertySymbols

Object.getOwnPropertySymbolsは名前の通り、自分自身にあるSymbolのキーの一覧を返します。enumerableは影響しません。


Reflect.ownKeys

Reflect.ownKeysObject.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))と同じ値、つまり自身にあるプロパティすべて(文字列のあとにSymbol)を返します。


その他

プロパティの順序は、どの手法をとっても表示されるものについては一貫していますが、どのような順序になるかは規定されていません。また、プロトタイプが存在するオブジェクトで、プロトタイプと違うenumerableを設定するとわけのわからないことになることもありますので、要注意です。


外部リンク