0Pricing
JavaScript Academy · レッスン

Proxy の実践的な活用例

バリデーション、ロギング、リアクティブなオブジェクトを作成します。

「Proxy の実践的な活用例」はCoddyKit上の無料JavaScript Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJavaScript Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 JavaScript Academyコースには全4レッスンが含まれています。

実践で使うProxy

ここからは、ProxyとReflectを組み合わせて、バリデーション、ログ記録、デフォルト値などの実際の問題を解決します。それぞれのパターンでは、オブジェクト自体を変更せずにプレーンオブジェクトをラップします。

バリデーションラッパー

スキーマを適用し、ルールに違反する書き込みを拒否します。不正なデータが保存されないため、targetはクリーンな状態を保てます。

function validated(obj, rules) {
  return new Proxy(obj, {
    set(target, prop, value, receiver) {
      const rule = rules[prop];
      if (rule && !rule(value)) {
        throw new TypeError('invalid value for ' + prop);
      }
      return Reflect.set(target, prop, value, receiver);
    }
  });
}

const user = validated({}, { age: v => v >= 0 });
user.age = 25;
console.log(user.age);
try { user.age = -1; } catch (e) { console.log(e.message); }

ログ記録ラッパー

ログを記録した後にReflectを通して処理を転送し、デバッグのためにすべての読み取りと書き込みを追跡します。

function logged(obj) {
  return new Proxy(obj, {
    get(t, p, r) { console.log('GET ' + p); return Reflect.get(t, p, r); },
    set(t, p, v, r) { console.log('SET ' + p + '=' + v); return Reflect.set(t, p, v, r); }
  });
}

const data = logged({ count: 0 });
data.count = 5;
console.log(data.count);

デフォルト値

存在しないプロパティに対して代替値を返すため、読み取り結果がundefinedになることはありません。

function withDefault(obj, fallback) {
  return new Proxy(obj, {
    get(t, p, r) {
      return p in t ? Reflect.get(t, p, r) : fallback;
    }
  });
}

const scores = withDefault({ ada: 90 }, 0);
console.log(scores.ada);
console.log(scores.unknown);

配列の負のインデックス

getトラップで負のインデックスを変換し、配列でPython形式の負のインデックスを使えるようにします。

function negIndex(arr) {
  return new Proxy(arr, {
    get(t, p, r) {
      const i = Number(p);
      if (Number.isInteger(i) && i < 0) {
        return Reflect.get(t, t.length + i, r);
      }
      return Reflect.get(t, p, r);
    }
  });
}

const list = negIndex(['a', 'b', 'c']);
console.log(list[-1]);
console.log(list[0]);

読み取り専用ビュー

読み取りはできても書き込みはできないオブジェクトを公開します。共有設定を保護する場合に便利です。

function readonly(obj) {
  return new Proxy(obj, {
    set() { console.log('blocked write'); return false; },
    deleteProperty() { console.log('blocked delete'); return false; }
  });
}

const config = readonly({ apiUrl: '/api' });
config.apiUrl = '/hacked';
console.log(config.apiUrl);

アクセス回数を数える

targetの外部にカウントを保存することで、各プロパティが読み取られた回数を追跡します。

function counted(obj) {
  const counts = {};
  const proxy = new Proxy(obj, {
    get(t, p, r) {
      counts[p] = (counts[p] || 0) + 1;
      return Reflect.get(t, p, r);
    }
  });
  return { proxy, counts };
}

const { proxy, counts } = counted({ x: 1 });
proxy.x; proxy.x; proxy.x;
console.log(counts.x);

計算による仮想プロパティ

保存されていない派生値を公開し、読み取るたびに最新の値を計算します。

const rect = new Proxy({ width: 4, height: 3 }, {
  get(t, p, r) {
    if (p === 'area') return t.width * t.height;
    return Reflect.get(t, p, r);
  }
});

console.log(rect.area);
rect.width = 10;
console.log(rect.area);

未知のプロパティの読み取り時に例外をスローする

存在しないプロパティがコードから読み取られたときに例外をスローし、入力ミスを早期に検出します。

function strict(obj) {
  return new Proxy(obj, {
    get(t, p, r) {
      if (typeof p === 'string' && !(p in t)) {
        throw new ReferenceError('unknown property: ' + p);
      }
      return Reflect.get(t, p, r);
    }
  });
}

const o = strict({ name: 'Ada' });
console.log(o.name);
try { console.log(o.naem); } catch (e) { console.log(e.message); }

関心事を組み合わせる

実際のラッパーでは、1つのハンドラーにバリデーションとログ記録を組み合わせることがよくあります。それぞれのトラップからReflectに処理を転送します。

const account = new Proxy({ balance: 0 }, {
  set(t, p, v, r) {
    if (p === 'balance' && v < 0) throw new RangeError('no overdraft');
    console.log(p + ' set to ' + v);
    return Reflect.set(t, p, v, r);
  }
});

account.balance = 100;
console.log(account.balance);
try { account.balance = -50; } catch (e) { console.log(e.message); }

これらのパターンが重要な理由

Proxyを使うと、元のオブジェクトや呼び出し元を汚染せずに、横断的な処理、バリデーション、ログ記録、デフォルト値、アクセス制御を追加できます。リアクティブフレームワークが状態の変化を監視する方法も、まさにこれです。透過的なインターセプトが必要なときに使用してください。

const observed = new Proxy({ n: 0 }, {
  set(t, p, v, r) {
    const ok = Reflect.set(t, p, v, r);
    console.log(p + ' is now ' + t[p]);
    return ok;
  }
});
observed.n = 1;
observed.n = 2;

理解度チェック

保存される前に無効な値を拒否するには、どのProxyトラップを使いますか。

まとめ:Proxyの実践的なユースケース

Proxyを実際の問題に適用しました。

  • バリデーションでは、setトラップが不正なデータを拒否します。
  • ログ記録では、Reflectを介して読み取りと書き込みを追跡します。
  • デフォルト値と仮想プロパティはgetトラップで実現します。
  • 読み取り専用ビュー、アクセス回数のカウント、厳格な入力ミスチェックも、すべてオブジェクトを透過的にラップして実現できます。

よくある質問

「Proxy の実践的な活用例」レッスンは無料ですか?

はい。「Proxy の実践的な活用例」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、JavaScript Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 JavaScript Academyコースには全4レッスンが含まれています。

「Proxy の実践的な活用例」で何を学びますか?

バリデーション、ロギング、リアクティブなオブジェクトを作成します。 ブラウザで直接実行するハンズオンコードでJavaScript Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

JavaScript Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのJavaScript Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「Proxy の実践的な活用例」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このJavaScript Academyレッスンでコードを書いて実行できますか?

はい。すべてのJavaScript Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. Proxy を作成する
  2. get と set のトラップ
  3. Reflect API
  4. Proxy の実践的な活用例
← JavaScript Academyに戻る