JavaScriptにおけるクロージャー

JavaScriptにおけるクロージャー

この記事ではJavaScriptにおけるクロージャーについて説明します。

YouTube Video

JavaScriptにおけるクロージャー

JavaScriptにおいて「クロージャー(closure)」は非常に重要で、強力な概念の一つです。クロージャーを理解することで、関数の動作やスコープ、さらにはJavaScriptの非同期処理やイベントハンドリングなど、多くの場面で役立つ知識が得られます。ここでは、クロージャーの基本的な定義から、具体的な例とその応用方法まで詳しく説明します。

クロージャーとは?

クロージャーとは、関数がそのスコープ外で呼び出されたときにも、自身が作成されたスコープ内の変数にアクセスできる仕組みのことを指します。クロージャーを利用することで、関数が外部の変数を「記憶」し続けることが可能になります。

クロージャーは、次の2つの要素によって成り立っています。

  1. 関数の定義(関数そのもの)

  2. 関数が定義されたスコープ(関数の外部にある変数や他の関数)

JavaScriptでは、関数が作成されたスコープ内の変数にアクセスできるという性質があるため、クロージャーが可能になります。

基本的な例

まず、クロージャーの基本的な例を見てみましょう。以下のコードでは、outerFunctioninnerFunctionという関数を返しています。重要なのは、innerFunctionouterFunctionのスコープ内で定義された変数countにアクセスできる点です。

 1function outerFunction() {
 2    let count = 0;
 3
 4    function innerFunction() {
 5        count++;
 6        console.log(`Current count: ${count}`);
 7    }
 8
 9    return innerFunction;
10}
11
12const counter = outerFunction();
13counter(); // Current count: 1
14counter(); // Current count: 2
15counter(); // Current count: 3

クロージャーの仕組み

上記の例で見たように、outerFunctionが実行された後もcountinnerFunctionによって保持されています。innerFunctionouterFunctionのスコープにアクセスし続けることができるため、countinnerFunction内で更新されます。これがクロージャーの基本的な仕組みです。

counter変数に代入されたのはinnerFunctionであり、outerFunctionは既に実行が完了しているにもかかわらず、countの状態が保存されていることが分かります。これは、JavaScriptが関数の定義時のスコープを「記憶」し続けるからです。

応用:プライベート変数としてのクロージャー

クロージャーは、オブジェクト指向プログラミングにおける「プライベート変数」のように利用することができます。通常、JavaScriptではオブジェクトのプロパティは外部から直接アクセス可能ですが、クロージャーを使えば、関数スコープ内の変数を外部から直接操作できなくすることが可能です。

次の例では、createCounter関数がクロージャーを使ってカウンターを作成し、プライベートな変数countを持つカウンターを返します。

 1function createCounter() {
 2    let count = 0;
 3
 4    return {
 5        increment: function() {
 6            count++;
 7            console.log(`Count: ${count}`);
 8        },
 9        decrement: function() {
10            count--;
11            console.log(`Count: ${count}`);
12        },
13        getCount: function() {
14            return count;
15        }
16    };
17}
18
19const myCounter = createCounter();
20myCounter.increment(); // Count: 1
21myCounter.increment(); // Count: 2
22myCounter.decrement(); // Count: 1
23console.log(myCounter.getCount()); // 1

この例では、countcreateCounter関数のスコープ内にあるため、外部から直接アクセスすることはできません。しかし、incrementdecrementメソッドを通じて操作することが可能です。このように、クロージャーを使うことで、JavaScriptにプライベート変数の概念を取り入れることができます。

クロージャーの実用例

コールバック関数との組み合わせ

クロージャーは、コールバック関数と組み合わせて非同期処理を管理する際によく使われます。たとえば、次のようなタイマーを使った例を考えてみましょう。

 1function startTimer(duration) {
 2    let timeLeft = duration;
 3
 4    function countdown() {
 5        console.log(`Time left: ${timeLeft} seconds`);
 6        timeLeft--;
 7
 8        if (timeLeft >= 0) {
 9            setTimeout(countdown, 1000);
10        }
11    }
12
13    countdown();
14}
15
16startTimer(5);
17// Time left: 5 seconds
18// Time left: 4 seconds
19// Time left: 3 seconds
20// Time left: 2 seconds
21// Time left: 1 second
22// Time left: 0 seconds

この例では、countdown関数がstartTimerのスコープ内にあるtimeLeft変数にアクセスしています。このように、クロージャーは時間が経過しても変数の状態を保持するため、タイマーのような非同期処理に非常に役立ちます。

イベントハンドラ

クロージャーは、イベントハンドラを設定する際にも便利です。次の例では、ボタンがクリックされた回数を記録するためにクロージャーが使用されています。

 1function setupClickCounter(buttonId) {
 2    let clickCount = 0;
 3
 4    const button = document.getElementById(buttonId);
 5    button.addEventListener('click', function() {
 6        clickCount++;
 7        console.log(`Button clicked ${clickCount} times`);
 8    });
 9}
10
11setupClickCounter('myButton');

この場合、クリックごとにclickCountが増加し、その値は記憶されます。クロージャーを使うことで、各ボタンに独立したカウンターを割り当てることができます。

結論

クロージャーは、JavaScriptの柔軟性と強力さを象徴する概念です。関数スコープに閉じ込められた変数を保持し、外部からアクセス可能な関数を通じてその変数に操作を加えることができます。この仕組みを理解し活用することで、JavaScriptのコーディングにおいてより高度な技術を身につけることができるでしょう。

クロージャーは、イベント処理、非同期処理、さらにはオブジェクト指向プログラミングの疑似実装に至るまで、さまざまな場面で応用されています。

YouTubeチャンネルでは、Visual Studio Codeを用いて上記の記事を見ながら確認できます。 ぜひYouTubeチャンネルもご覧ください。

YouTube Video