INDEX
ハンドラによる挙動の制御とは?

ハンドラは、JavaScriptのProxyでオブジェクトの操作を制御するために使うオブジェクトです。
Proxyを使うと、プロパティの読み取り、書き込み、削除、存在確認、関数呼び出しなどに対して、独自の処理を挟むことができます。
この独自処理を定義する関数はトラップ(trap)と呼ばれます。
ハンドラの基本的な仕組み
Proxyは、操作対象となるオブジェクトと、挙動を制御するハンドラを指定して作成します。
基本構文
const target = {};
const handler = {
get(target, prop) {
console.log(`プロパティ ${prop} にアクセスしました`);
return target[prop];
},
set(target, prop, value) {
console.log(`プロパティ ${prop} に値 ${value} を設定しました`);
target[prop] = value;
return true;
}
};
const proxy = new Proxy(target, handler);
proxy.name = "Alice";
console.log(proxy.name);
// プロパティ name に値 Alice を設定しました
// プロパティ name にアクセスしました
// Alice
この例では、getとsetトラップを定義しています。
proxy.name = "Alice"でsetトラップが実行されます。proxy.nameを読み取るとgetトラップが実行されます。- 通常のオブジェクト操作にログ出力を追加できます。
代表的なハンドラトラップの一覧
| トラップ名 | 動作するタイミング | 使用例 |
|---|---|---|
get |
プロパティを取得するとき | 存在しないプロパティにデフォルト値を返す。 |
set |
プロパティへ値を設定するとき | 値のバリデーションを行う。 |
has |
in演算子で確認するとき |
プロパティの存在確認を制御する。 |
deleteProperty |
プロパティを削除するとき | 特定のプロパティの削除を禁止する。 |
apply |
関数を呼び出すとき | 関数実行前後に処理を追加する。 |
construct |
newで呼び出すとき |
インスタンス作成時の動作を制御する。 |
getトラップの使用例
getトラップは、プロパティを読み取るときに実行されます。
次の例では、存在しないプロパティにアクセスした場合にデフォルト値を返します。
const target = {
name: "Alice",
age: 25
};
const handler = {
get(target, prop) {
if (prop in target) {
return target[prop];
}
console.log(`プロパティ ${prop} は存在しません`);
return "デフォルト値";
}
};
const proxy = new Proxy(target, handler);
console.log(proxy.name);
console.log(proxy.gender);
// Alice
// プロパティ gender は存在しません
// デフォルト値
このように、プロパティが存在しない場合の処理を自由に設定できます。
setトラップの使用例
setトラップは、プロパティへ値を設定するときに実行されます。
値の型チェックや入力チェックを行いたい場合に便利です。
const target = {
name: "Alice",
age: 25
};
const handler = {
set(target, prop, value) {
if (prop === "age" && typeof value !== "number") {
console.log("エラー: 年齢は数値でなければなりません");
return false;
}
target[prop] = value;
return true;
}
};
const proxy = new Proxy(target, handler);
proxy.age = 30;
proxy.age = "30";
// エラー: 年齢は数値でなければなりません
setトラップでは、処理が成功した場合はtrue、失敗した場合はfalseを返します。
deletePropertyトラップの使用例
deletePropertyトラップは、delete演算子でプロパティを削除するときに実行されます。
const target = {
name: "Alice",
age: 25
};
const handler = {
deleteProperty(target, prop) {
if (prop === "age") {
console.log("エラー: ageプロパティは削除できません");
return false;
}
delete target[prop];
return true;
}
};
const proxy = new Proxy(target, handler);
delete proxy.age;
delete proxy.name;
// エラー: ageプロパティは削除できません
この例では、ageだけを削除できないようにしています。
applyトラップの使用例
applyトラップは、関数をProxyで包んだときに利用できます。
関数が呼び出される前後に処理を追加したい場合に便利です。
function sum(a, b) {
return a + b;
}
const handler = {
apply(target, thisArg, argumentsList) {
console.log(`関数が呼び出されました: ${argumentsList.join(", ")}`);
return target(...argumentsList);
}
};
const proxy = new Proxy(sum, handler);
console.log(proxy(5, 10));
// 関数が呼び出されました: 5, 10
// 15
ログ出力、引数チェック、実行時間の計測などに応用できます。
Proxyを使うときの注意点
Proxyは強力ですが、通常のオブジェクトよりも挙動が複雑になります。
- 処理の流れが分かりにくくなる場合がある。
- 大量に使うとパフォーマンスに影響することがある。
- デバッグ時に、実際にどの処理が実行されているか追いにくい場合がある。
- 単純な値チェックだけなら、通常の関数やクラスで十分な場合もある。
初心者が知っておきたいポイント
Proxyはオブジェクト操作を横取りして制御できる仕組みである。- ハンドラには
getやsetなどのトラップを定義する。 getは読み取り、setは書き込み、deletePropertyは削除時に動作する。applyを使うと関数呼び出しも制御できる。- 便利だが、必要な場面に絞って使うことが重要である。
まとめ
- ハンドラは
Proxyの挙動を制御するためのオブジェクトである。 - トラップを定義することで、プロパティの取得・設定・削除などを制御できる。
getやsetは特によく使われるトラップである。applyを利用すると関数呼び出しの動作もカスタマイズできる。Proxyは強力だが、複雑になりやすいため使いどころを見極める必要がある。