導入
JavaScriptでオブジェクトのプロパティを列挙する際、Object.keys()やfor…in文を使い分けていませんか?しかし、これらには「シンボル(Symbol)が含まれない」「継承されたプロパティまで混ざる」といった制限があります。今回解説するReflect.ownKeysは、オブジェクトが持つすべてのプロパティを網羅的に取得できる強力なメソッドです。メタプログラミングの第一歩として、この技術を習得することで、ライブラリ開発や複雑なデータ処理の柔軟性が飛躍的に向上します。
基礎知識
Reflectは、JavaScriptの操作をプログラム的に制御するための組み込みオブジェクトです。その中でもReflect.ownKeysは、指定したオブジェクトの「自分のプロパティ」すべてを配列で返します。
ここでの「すべて」とは、以下の3つを指します。
1. 文字列キー(通常のプロパティ名)
2. シンボルキー(Symbol型で定義されたプロパティ)
3. 列挙不可プロパティ(enumerable: falseの設定がされたもの)
これらを一度に取得できるのは、標準APIの中ではReflect.ownKeysだけです。
実装/解決策
Reflect.ownKeysを使う際は、対象のオブジェクトを引数に渡すだけです。戻り値は常に配列となるため、mapやforEachで簡単にループ処理が可能です。特に「非公開プロパティを隠蔽してデータ処理を行いたい」場合や、「オブジェクトの完全なコピーやシリアライズを行いたい」場合に非常に有効です。
サンプルプログラム
以下のコードは、通常のプロパティとシンボル、さらに列挙不可のプロパティを混ぜたオブジェクトから、Reflect.ownKeysを使ってすべてのキーを抽出する例です。
// 1. テスト用のオブジェクトを作成
const user = {
name: '田中',
[Symbol('id')]: 12345 // シンボルキー
};
// 2. 列挙不可のプロパティを追加
Object.defineProperty(user, 'secretKey', {
value: 'hidden_value',
enumerable: false // 通常のObject.keysでは取得できない
});
// 3. Reflect.ownKeysで全キーを取得
const keys = Reflect.ownKeys(user);
// 結果を表示
keys.forEach(key => {
// シンボルと文字列を区別して出力
const type = typeof key === 'symbol' ? 'Symbol' : 'String';
console.log(`キー名: ${key.toString()}, 型: ${type}, 値: ${user[key]}`);
});
応用・注意点
注意点として、Reflect.ownKeysはあくまで「そのオブジェクト自身」が持つキーのみを返します。プロトタイプチェーンを遡って継承されたプロパティを取得することはないため、用途に応じてObject.getPrototypeOfと組み合わせる必要があります。また、セキュリティの観点から、外部ライブラリなどのオブジェクトに対してむやみに全プロパティを抽出すると、意図しない内部変数にアクセスしてしまうリスクがあります。必要なプロパティのみをフィルタリングする処理をセットで実装するのが、現場での安全な開発スタイルです。