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を設定するとわけのわからないことになることもありますので、要注意です。

外部リンク