ProxyとReflectの設計戦略：JavaScriptオブジェクトの操作を傍受・制御するメタプログラミングの核心

## 概要

JavaScriptの `Proxy` と `Reflect` は、オブジェクトの操作を**透明かつ動的に監視・操作・再定義**できる構文的インターフェースである。  
これにより、以下のような構造制御が可能になる：

- アクセスログの記録 / 非公開プロパティのガード
- 動的バリデーション / エラーハンドリング
- APIレスポンスの型補正 / 自動変換
- Vue.jsなどリアクティブシステムの根幹処理

この記事では、**ProxyとReflectの構文と設計的活用戦略**を体系的に整理する。

---

## Proxyの基本構造

```js
const target = { name: 'Toto' };

const handler = {
  get(target, prop) {
    console.log(`get ${prop}`);
    return target[prop];
  }
};

const proxy = new Proxy(target, handler);

proxy.name; // → get name → 'Toto'
```

→ ✅ `proxy.name` の呼び出しを `handler.get()` が傍受する

---

## サポートされるトラップ一覧

| 操作              | トラップ名   |
|-------------------|--------------|
| プロパティ取得     | `get`        |
| プロパティ設定     | `set`        |
| 存在確認（in演算子）| `has`        |
| 削除               | `deleteProperty` |
| 列挙（for...in）   | `ownKeys`    |
| Object.keys        | `ownKeys`    |
| Object.getOwnPropertyDescriptor | `getOwnPropertyDescriptor` |
| プロパティ定義     | `defineProperty` |
| 関数呼び出し       | `apply`      |
| newによる生成      | `construct`  |

---

## Reflect の役割

```js
Reflect.get(target, prop, receiver);
Reflect.set(target, prop, value, receiver);
Reflect.has(target, prop);
```

- ✅ 通常のオブジェクト操作と同じ動作を返す「安全な内部API」
- ✅ Proxyハンドラー内で `Reflect` を使うことで、**元の操作に委譲**できる
- ✅ `return Reflect.set(...)` などで、**トラップ内でも“自然な挙動”を保てる**

---

## 実務ユースケース①：不正プロパティのアクセスガード

```js
const guarded = new Proxy({}, {
  get(_, prop) {
    if (prop.startsWith('_')) {
      throw new Error(`Access to private property "${prop}" denied`);
    }
    return Reflect.get(...arguments);
  }
});

guarded.name = 'Toto';
guarded._secret; // ❌ Error
```

---

## 実務ユースケース②：自動バリデーション

```js
function createValidatedUser() {
  const data = {};
  return new Proxy(data, {
    set(obj, key, value) {
      if (key === 'age' && typeof value !== 'number') {
        throw new TypeError('age must be a number');
      }
      return Reflect.set(obj, key, value);
    }
  });
}

const user = createValidatedUser();
user.age = 28; // ✅
user.age = 'twenty'; // ❌ TypeError
```

---

## 実務ユースケース③：APIレスポンスの補正

```js
function normalizeAPIResponse(obj) {
  return new Proxy(obj, {
    get(target, key) {
      const val = Reflect.get(target, key);
      return val === null || val === undefined ? 'N/A' : val;
    }
  });
}

const res = normalizeAPIResponse({ name: null, age: 30 });
console.log(res.name); // N/A
console.log(res.age);  // 30
```

---

## Vueのリアクティブ実装の核心もProxy

```js
const state = new Proxy({ count: 0 }, {
  get(target, key) {
    trackDependency(key);
    return Reflect.get(target, key);
  },
  set(target, key, value) {
    const result = Reflect.set(target, key, value);
    triggerUpdate(key);
    return result;
  }
});
```

→ ✅ `get` で依存トラッキング、`set` で更新通知を実装

---

## よくあるミスと注意点

### ❌ Proxy は “透過的ではない”

- `proxy instanceof TargetConstructor` → false になる可能性
- JSON.stringify(proxy) → 期待通りにならないケースあり

---

### ❌ `Reflect` を使わず `target[prop] = value` などすると副作用が起こりやすい

→ ✅ 常に `Reflect` 経由で基本操作を委譲すべき

---

## 設計判断フロー

```text
① オブジェクトの操作を監視・制御したい？ → Proxy

② 元の操作を再現しつつ傍受したい？ → Reflect を併用

③ ロギング / バリデーション / ガード処理を構造的に挟みたい？ → Proxy一択

④ 構造全体に一律のルールを敷きたい？ → Proxyで構造単位を制御

⑤ Vue的なリアクティブ設計をしたい？ → get/setトラップで実装可能
```

---

## 結語

`Proxy` は、単なる“オブジェクトをラップする構文”ではない。  
それは **オブジェクトの意味と挙動を再構成できる、構文的ミドルウェア**である。

- `Proxy` は傍受者であり、
- `Reflect` は原点への導線である。

**構造をそのまま使うだけではなく、操作の意味そのものを再設計する。**  
それが `Proxy` / `Reflect` を使う意味であり、JavaScriptのメタプログラミングの本質である。