Proxyの本質を理解する：オブジェクトの振る舞いを動的に設計するJavaScriptの構文戦略

## 概要

JavaScriptの `Proxy` は、「あるオブジェクトに対するすべての操作」を**横から捕捉し、任意の振る舞いに書き換える**ことができる。

つまり、ただのデータ構造だったオブジェクトが、**知能を持った“反応型オブジェクト”に進化する。**

Vue3のリアクティブ設計、型チェックの強化、アクセスログの記録、APIラッパーなど、あらゆる“動的挙動”の裏に潜むのが `Proxy` だ。

本記事では、構文から設計まで、**Proxyを使うべき場面・使わないべき場面を含めて構造的に理解**する。

---

## 対象環境

```text
ES6以降（Node.js / モダンブラウザ）
```

---

## Proxyの基本構文

```js
const proxy = new Proxy(target, handler);
```

- `target`: 操作対象となるオブジェクト
- `handler`: どのように振る舞いを上書きするかの定義

---

## 最小構成例：ログを出力するProxy

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

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

const proxy = new Proxy(target, handler);

console.log(proxy.name); // ログ + 値出力
```

---

## サポートされるTrap一覧

| Trap名      | 捕捉対象                           |
|-------------|------------------------------------|
| `get`       | プロパティの取得                  |
| `set`       | プロパティの代入                  |
| `has`       | `in` 演算子                       |
| `deleteProperty` | `delete` 演算子              |
| `apply`     | 関数の呼び出し                    |
| `construct` | `new` によるコンストラクタ呼び出し |
| `ownKeys`   | `Object.keys()` など              |
| `getOwnPropertyDescriptor` | `Object.getOwnPropertyDescriptor()` |

---

## ユースケース①：動的なバリデーション

```js
const user = {
  age: 0
};

const validator = {
  set(obj, prop, value) {
    if (prop === 'age' && typeof value !== 'number') {
      throw new TypeError('age must be a number');
    }
    obj[prop] = value;
    return true;
  }
};

const proxyUser = new Proxy(user, validator);
proxyUser.age = 30;      // ✅ OK
proxyUser.age = 'young'; // ❌ TypeError
```

→ ✅ 型安全な設計が可能に

---

## ユースケース②：存在しないプロパティのハンドリング

```js
const fallback = new Proxy({}, {
  get: (obj, prop) => prop in obj ? obj[prop] : `未定義：${prop}`
});

console.log(fallback.language); // '未定義：language'
```

→ ✅ 安全に “未定義アクセス” を検出・補完可能

---

## ユースケース③：自動バインディング（Vueのようなリアクティブ設計）

```js
function reactive(obj) {
  return new Proxy(obj, {
    get(target, prop) {
      console.log(`依存追跡: ${prop}`);
      return target[prop];
    },
    set(target, prop, value) {
      console.log(`更新検知: ${prop} = ${value}`);
      target[prop] = value;
      return true;
    }
  });
}

const state = reactive({ count: 0 });
state.count++; // get → set → 更新検知ログ
```

→ ✅ Vue 3の `reactive()` はまさにこの形

---

## ユースケース④：関数呼び出しの拡張（apply）

```js
function greet(name) {
  return `Hello, ${name}`;
}

const logged = new Proxy(greet, {
  apply(target, thisArg, args) {
    console.log(`Call: ${args[0]}`);
    return target.apply(thisArg, args);
  }
});

logged('toto'); // ログ + 呼び出し
```

→ ✅ 関数に“副作用”を追加したいときに便利

---

## ユースケース⑤：構築を制御（construct）

```js
class Person {
  constructor(name) {
    this.name = name;
  }
}

const Protected = new Proxy(Person, {
  construct(target, args) {
    if (!args[0]) throw new Error('name is required');
    return new target(...args);
  }
});

new Protected('toto'); // OK
new Protected();       // ❌ Error
```

→ ✅ コンストラクタの検査・注入処理に使える

---

## 注意点・落とし穴

### ❌ Proxyを多用するとパフォーマンスが低下する可能性

- リアクティブ構造を大規模に作る場合は `Proxy` の使いすぎに注意

### ❌ Proxyはオブジェクトの“見た目”を変えない

```js
typeof proxy; // 'object'
Array.isArray(proxy); // ❌ false（元が配列でも）
```

→ ✅ 必要に応じて `Reflect` を使って正確に模倣する

---

## Reflectと組み合わせて安全に

```js
const safeProxy = new Proxy(obj, {
  get: (target, prop) => Reflect.get(target, prop),
  set: (target, prop, value) => Reflect.set(target, prop, value)
});
```

→ ✅ Proxyの中で**本来の操作を正しく行う**ために `Reflect` を活用

---

## 結語

`Proxy` は単なる構文ではない。  
それは「**JavaScriptのあらゆる振る舞いをオーバーライドできるインターセプター**」であり、  
設計者に “オブジェクトの真の振る舞い” を定義する力を与える。

- バリデーションの自動化  
- 隠蔽的デザイン  
- リアクティブ構造  
- メタ的ロジックの挿入

これらをコードの中に安全に、かつ動的に埋め込むための道具が Proxy である。

設計とは「コードを書く」ことではない。  
**「コードがどう振る舞うか」を定義すること**である。