JavaScript上級

上級 JavaScriptで学ぶイベント駆動設計|練習問題編

導入

イベント駆動設計は、ユーザーインターフェースや非同期処理を扱う際に非常に重要なアプローチです。特に、JavaScriptを使用したフロントエンド開発においては、イベントに基づく処理が中心となります。本記事では、実際の業務で直面するシナリオを通じて、イベント駆動設計の実践的な側面を探ります。

教科書レベルの解説(イベント駆動設計)

重要な概念の整理

イベント駆動設計では、アプリケーションの状態変化をイベントとして捉え、これに対するリスナーを設定します。これにより、コードの可読性やメンテナンス性が向上し、機能の追加や変更が容易になります。特に、ユーザーの操作や外部からのデータ受信など、非同期の要素を扱う際にその効果が顕著に現れます。

コード例(JavaScript)


class EventEmitter {
    constructor() {
        this.events = {};
    }

    on(event, listener) {
        if (!this.events[event]) {
            this.events[event] = [];
        }
        this.events[event].push(listener);
    }

    emit(event, ...args) {
        if (this.events[event]) {
            this.events[event].forEach(listener => listener(...args));
        }
    }
}

// 使用例
const emitter = new EventEmitter();

emitter.on('dataReceived', (data) => {
    console.log('データを受信:', data);
});

emitter.emit('dataReceived', { id: 1, message: 'Hello, World!' });

コードの行ごとの解説

  1. class EventEmitter { – イベントを管理するクラスを定義します。
  2. constructor() { this.events = {}; } – イベントを格納するオブジェクトを初期化します。
  3. on(event, listener) { ... } – 指定したイベントにリスナーを追加します。
  4. emit(event, ...args) { ... } – イベントを発火し、登録されたリスナーを呼び出します。
  5. emitter.on('dataReceived', (data) => { ... }); – ‘dataReceived’ イベントに対するリスナーを設定します。
  6. emitter.emit('dataReceived', { id: 1, message: 'Hello, World!' }); – イベントを発火し、リスナーにデータを渡します。

練習問題編

以下の練習問題に挑戦し、イベント駆動設計の理解を深めてください。

  1. 問題1: EventEmitterクラスに、特定のイベントのリスナーを削除するメソッドを追加してください。
  2. 問題2: emitメソッドを改良し、リスナーが返す値を収集して返すようにしてください。
  3. 問題3: イベントが発火した回数をカウントし、emitメソッドでその回数をログに出力する機能を追加してください。

模範解答と解説

問題1: リスナーを削除するメソッドは、リスナーの参照を保持し、リスナーが一致する場合に削除します。


removeListener(event, listener) {
    if (!this.events[event]) return;
    this.events[event] = this.events[event].filter(l => l !== listener);
}

問題2: emitメソッドを改良することで、リスナーが返す結果を配列に格納し、最終的にその配列を返します。


emit(event, ...args) {
    const results = [];
    if (this.events[event]) {
        this.events[event].forEach(listener => results.push(listener(...args)));
    }
    return results;
}

問題3: emitメソッドにカウント機能を追加することで、イベントの発火回数を追跡します。


let count = 0;
emit(event, ...args) {
    count++;
    console.log(`Event ${event} has been emitted ${count} times.`);
    // 既存のemit処理...
}

まとめ

  • イベント駆動設計は、コードの可読性とメンテナンス性を向上させます。
  • リスナーの管理を適切に行うことで、イベントの発火時に柔軟に対応できます。
  • 実務での具体的なシナリオを通じて、イベント駆動設計の重要性を理解できます。