Proxy とは何か(まずイメージから)
Proxy は、
「あるオブジェクトの前に立って、そのオブジェクトへの操作を横取り・監視・カスタマイズできる“番人”」
のような仕組みです。
普通はこうです。
const user = { name: "Alice" };
user.name = "Bob"; // 書き込み
console.log(user.name); // 読み取り
delete user.name; // 削除
JavaScriptProxy を使うと、この「読み取り」「書き込み」「削除」などのタイミングに
自分の処理を差し込めます。
ここが重要です。
Proxy は「オブジェクトに対する操作にフック(hook)をかける仕組み」 です。
ログをとる、値を検証する、自動補完する、などを中心でまとめて行うことができます。
基本構文:new Proxy(target, handler) の 2 つの役
target(ターゲット)とは
target は「本物のオブジェクト」です。
const user = { name: "Alice", age: 20 };
JavaScriptこの user に対して Proxy を作るとき、target は user になります。
実際にデータを持っているのは target 側です。
handler(ハンドラ)とは
handler は、
「どの操作を、どう横取りするか」を定義するオブジェクトです。
const handler = {
get(target, prop, receiver) {
// プロパティを「読む」ときに呼ばれる
},
set(target, prop, value, receiver) {
// プロパティを「書く」ときに呼ばれる
},
};
JavaScriptこの handler の中に、get, set, deleteProperty, has, ownKeys …など
いろいろな「罠(trap)」メソッドを書くことで、
target への操作をカスタマイズできます。
Proxy を作って使ってみる
最小の例を見てみます。
const user = { name: "Alice", age: 20 };
const handler = {
get(target, prop, receiver) {
console.log(`get: ${String(prop)}`);
return target[prop]; // 本物にアクセス
},
};
const proxy = new Proxy(user, handler);
console.log(proxy.name); // get: name → "Alice"
console.log(proxy.age); // get: age → 20
JavaScriptproxy.name と書いていますが、
実際には:
- handler.get が呼ばれる
- ログを出す
target[prop]で本物userから値を取って返す
という流れで動いています。
ここが重要です。
Proxy は「target と同じ見た目で振る舞うが、操作の通り道に自分の処理を挟める“代理人”」
だとイメージしてください。
よく使う trap:get / set の基本と活用
get trap(プロパティ取得の横取り)
obj.prop や obj["prop"] で取得するときに呼ばれます。
const user = { name: "Alice", age: 20 };
const handler = {
get(target, prop, receiver) {
console.log(`プロパティ ${String(prop)} が読み取られました`);
return target[prop];
},
};
const proxy = new Proxy(user, handler);
console.log(proxy.name);
// ログ: プロパティ name が読み取られました
// 出力: Alice
JavaScriptset trap(プロパティ代入の横取り)
obj.prop = value のような代入のときに呼ばれます。
const user = { name: "Alice", age: 20 };
const handler = {
set(target, prop, value, receiver) {
console.log(`プロパティ ${String(prop)} に ${value} が代入されました`);
target[prop] = value;
return true; // 成功したことを示す(ほぼお約束)
},
};
const proxy = new Proxy(user, handler);
proxy.age = 25;
// ログ: プロパティ age に 25 が代入されました
console.log(user.age); // 25(target 側もちゃんと更新されている)
JavaScript例:存在しないプロパティを読むときの「優しいデフォルト」
ユーザー設定などで「存在しない設定を読んだらデフォルトを返したい」ケースがあります。
const settings = { theme: "dark" };
const handler = {
get(target, prop, receiver) {
if (prop in target) {
return target[prop];
}
return "(デフォルト値)";
},
};
const proxy = new Proxy(settings, handler);
console.log(proxy.theme); // "dark"
console.log(proxy.font); // "(デフォルト値)"
JavaScript本来なら settings.font は undefined になりますが、
Proxy の get で「なかったときの値」を差し込めています。
例:書き込み時に型チェック(バリデーション)
年齢は数値で、かつ 0 以上でなければダメ、という制約を入れてみます。
const user = { name: "Alice", age: 20 };
const handler = {
set(target, prop, value, receiver) {
if (prop === "age") {
if (typeof value !== "number" || value < 0) {
throw new Error("age は 0 以上の数値でなければなりません");
}
}
target[prop] = value;
return true;
},
};
const proxy = new Proxy(user, handler);
proxy.age = 30; // OK
proxy.age = -5; // エラー
proxy.age = "若い"; // エラー
JavaScriptここが重要です。
Proxy を使うと、「オブジェクトへのアクセスや変更に対して、一括でルールを差し込める」。
いちいちセッター関数を通さなくても、普通のプロパティアクセスの形で利用者は書けます。
もう少し踏み込んだ trap:delete / has / ownKeys など
deleteProperty trap(削除の横取り)
delete obj.prop のときに呼ばれます。
const user = { name: "Alice", secret: "秘密" };
const handler = {
deleteProperty(target, prop) {
if (prop === "secret") {
console.log("secret は削除させません");
return false; // false を返すと削除失敗(strict モードだとエラー)
}
delete target[prop];
return true;
},
};
const proxy = new Proxy(user, handler);
delete proxy.name; // 削除される
delete proxy.secret; // secret は削除させません
JavaScripthas trap(in 演算子の横取り)
prop in obj で呼ばれます。
const user = { name: "Alice", password: "1234" };
const handler = {
has(target, prop) {
if (prop === "password") {
return false; // 存在していても「ないことにする」
}
return prop in target;
},
};
const proxy = new Proxy(user, handler);
console.log("name" in proxy); // true
console.log("password" in proxy); // false(存在しているのに隠している)
JavaScriptownKeys trap(Object.keys などの横取り)
オブジェクトのキー一覧を取得するときに呼ばれます。
const user = { name: "Alice", password: "1234" };
const handler = {
ownKeys(target) {
// password を一覧に出さない
return Object.keys(target).filter((key) => key !== "password");
},
};
const proxy = new Proxy(user, handler);
console.log(Object.keys(proxy)); // ["name"]
JavaScriptここが重要です。
delete / has / ownKeys を組み合わせると、「外から見えるプロパティ」を自在にコントロールできる。
公開したくない情報を隠す、内部用のデータを外に見せない、といった使い方ができます。
配列や関数も Proxy できる
配列の操作を監視する
配列に対する push やインデックスアクセスも、そのまま Proxy の対象です。
const numbers = [];
const handler = {
set(target, prop, value, receiver) {
console.log(`index ${prop} に ${value} をセット`);
target[prop] = value;
return true;
},
};
const proxy = new Proxy(numbers, handler);
proxy.push(1); // index 0 に 1 をセット
proxy.push(2); // index 1 に 2 をセット
JavaScriptpush が内部的に target[target.length] = value のような書き込みを行うため、set trap が発火します。
関数に対する Proxy(apply / construct)
関数呼び出しを横取りすることもできます。
function sum(a, b) {
return a + b;
}
const handler = {
apply(target, thisArg, args) {
console.log("呼び出しログ:", args);
const result = target(...args);
console.log("結果:", result);
return result;
},
};
const proxy = new Proxy(sum, handler);
proxy(1, 2); // 呼び出しログ: [1, 2]
// 結果: 3
JavaScriptapply trap は、proxy(…) のように関数として呼び出されたときに発火します。
実務での使いどころ(どこから触ると良いか)
実務でよくある用途のイメージ
初心者が実務で Proxy に出会うのは、たとえばこんな場面です。
設定オブジェクトや状態オブジェクトに対して、
「不正な値や存在しないキーへのアクセス」を検知したいとき
デバッグ用に、特定のオブジェクトへのアクセスを全部ログに出したいとき
内部的に「Vue/Pinia/ MobX」などのリアクティブシステム(状態管理)で、
Proxy が使われているのを見るとき
特に Vue 3 などでは、Proxy を使って
「プロパティが変化したことを検知 → 画面を再描画」
という仕組みを作っています。
初学者として「どこまで理解しておくといいか」
正直に言うと、
Proxy は ES6 の中でも、わりと“応用寄りの機能” です。
初心者の段階では、次のポイントが押さえられていれば十分です。
Proxy の構文:new Proxy(target, handler)
主な trap:get と set が「読み取り」「書き込み」を横取りする
使いどころ:
ログを取る、バリデーションする、ないプロパティにデフォルトを返す、
といった「共通ルール」を一箇所に集約できる
「Vue などのフレームワークは、裏で Proxy を使っていることが多い」
というざっくりした理解
そのうえで、実際に小さな Proxy を一つ書いてみるのが一番です。
例えば:
あるオブジェクトに対して
・読み取られたプロパティ名をログに出す
・書き込まれた値の型をチェックする
という handler を自作して動かしてみるだけで、
Proxy のイメージはかなりクリアになります。
まとめ
Proxy の本質は、
「オブジェクトへの操作(読み取り・書き込み・削除・関数呼び出しなど)を、丸ごと横取りしてカスタマイズできる仕組み」
であることです。
押さえておきたいポイントは次の通りです。
new Proxy(target, handler) で作る。target は本体、handler は「横取りのルール」
get trap で読み取りを、set trap で書き込みを横取りできる
deleteProperty, has, ownKeys, apply などを使えば、削除や in 演算子、キー列挙、関数呼び出しもコントロールできる
Proxy は「オブジェクトの前に立つ番人」のイメージ。
“存在しないプロパティのデフォルト値”“不正な値の拒否”“アクセスログ”などを一括管理できる
配列や関数も Proxy できる。Vue などのライブラリの内部では、状態の監視・リアクティブ化に使われていることが多い
まずは、get と set だけ使ったシンプルな Proxy を一つ書いて、
「proxy 経由の操作が全部 handler に流れてくる感覚」を掴んでみてください。
それが体で分かると、
「Proxy は難しい“黒魔術”」ではなく、
「オブジェクト操作をコントロールするための強力なスイッチ」として見えるようになります。
