【ITニュース解説】Closure in js
2025年09月25日に「Dev.to」が公開したITニュース「Closure in js」について初心者にもわかりやすく解説しています。
ITニュース概要
JavaScriptでは変数は「ローカル」(関数内)か「グローバル」(関数外)に属する。クロージャを使うと、グローバル変数を関数内で「プライベート」化でき、外部から触れられない専用変数として扱える。これにより、関数の独立性を高め安全にコードを書ける。
ITニュース解説
JavaScriptでプログラムを記述する際、変数がどこからアクセスできるか、そしてその変数がいつまで有効であるかという概念は非常に重要である。この変数の「使える範囲」をスコープと呼ぶ。JavaScriptの変数は、主にローカルスコープとグローバルスコープという二つの範囲に属しており、これらのスコープを理解することが、整理され、意図したとおりに動作するコードを書くための基礎となる。
まず、ローカルスコープについて説明する。ローカルスコープとは、関数の中で定義された変数がアクセスできる範囲のことである。関数内でletやconst、あるいはvarキーワードを使って変数を宣言すると、その変数はその関数専用の「ローカル変数」となる。このローカル変数は、それを定義した関数の内部からのみアクセス可能であり、関数の外部からはその変数の存在自体を知ることはできない。そのため、ローカル変数は「プライベートな変数」と表現されることがある。関数が実行を終えると、その中で定義されたローカル変数もメモリから解放され、消滅する。
具体的な例として、以下のコードを見てみよう。
1function myFunction() { 2 let a = 4; 3 return a * a; 4}
このmyFunction内で宣言されているaはローカル変数である。変数aはmyFunctionの内部でのみ使用され、その関数が呼び出されるたびに新しく作成され、関数が終了すると同時に消滅する。myFunction()を呼び出して計算結果を得ることはできるが、myFunction()の外でaの値に直接アクセスしようとすると、参照エラーが発生する。これは、aがmyFunctionのローカルスコープに閉じ込められているためである。
次に、グローバルスコープについて説明する。グローバルスコープとは、関数の外で定義された変数がアクセスできる範囲のことである。プログラムのどの部分からもアクセスできる変数を「グローバル変数」と呼ぶ。グローバル変数は、プログラム内のどの関数からも参照したり、その値を変更したりすることが可能である。
以下のコードはグローバル変数の例である。
1let a = 4; 2function myFunction() { 3 return a * a; 4}
このコードでは、aは関数の外で宣言されているためグローバル変数である。myFunctionが実行される際、その内部にaという変数が定義されていなくても、グローバルスコープに存在するaを参照して計算を行うことができる。ウェブページ上では、グローバル変数はそのページ全体に属し、ページ内のすべてのスクリプトから利用したり、値を変更したりすることが可能である。複数のスクリプト間で情報を共有する際には便利だが、予期せぬ場所で変数の値が変更されてしまい、それが原因でバグが発生する可能性も潜在的に存在している。
ローカル変数とグローバル変数は、同じ名前を持つことが可能であるという点も理解しておくべきである。もし、グローバル変数としてlet x = 10;が定義されており、さらにある関数内でlet x = 5;というローカル変数が定義された場合、これらは全く別の変数として扱われる。関数内でxを参照すると、それはローカル変数であるx(値は5)を指し、グローバル変数のx(値は10)には影響を与えない。この場合、ローカル変数がグローバル変数を「隠蔽」していると表現される。これにより、他の部分のコードに影響を与えることなく、関数内で安全に同じ名前の変数を使用できるようになる。
ここで、JavaScriptの重要な概念である「クロージャ」について触れる。ニュース記事が指摘するように、「グローバル変数をクロージャを使ってローカル(プライベート)にすることができる」ことや、「クロージャによって関数が『プライベート』な変数を持てるようになる」という点がクロージャの核心的な能力である。
通常のローカル変数は、それを定義した関数が実行を終えるとメモリから解放され、アクセスできなくなる。しかし、クロージャを用いると、この「通常は消滅するはずのローカル変数」を、関数が実行を終えた後も「生き続けさせる」ことが可能になる。これは、関数がその定義された「環境」、つまり関数が作成された時点でのスコープ内にあるすべてのローカル変数を記憶し続けることで実現される。
具体的には、ある関数が別の関数を返し、その返された関数が外側の関数が持っていたローカル変数を参照している場合、そのローカル変数は外側の関数が実行を終えても消滅せず、返された関数が参照し続ける限りメモリ上に保持される。このメカニズムにより、関数は外部から直接アクセスできない「プライベートな変数」を持つことができるようになる。
例えば、カウンターを作成する関数を考えてみよう。外側の関数でcountというローカル変数を定義し、内側の関数(返される関数)がそのcount変数をインクリメントして返すようにする。外側の関数は一度実行されれば終了するが、返された内側の関数はcountの値を記憶し続け、呼び出されるたびにその値を更新できる。このcount変数は、外側の関数によって定義されたローカル変数であるため、外部から直接countの値にアクセスしたり、勝手に変更したりすることはできない。しかし、返された内側の関数を通じてのみ、その値を安全に操作できる。
このように、クロージャは特定のデータ(変数)を隠蔽し、限定された方法でのみアクセスや変更を許可するプライベートなメカニズムを提供する。これにより、グローバル変数の乱用によって引き起こされる名前の衝突や意図しない値の変更といった問題を避けることができる。グローバル変数をプライベートな状態としてカプセル化し、それを操作するための特定のインターフェース(返された関数)だけを外部に公開することで、プログラムの安全性と保守性を高めることが可能となる。
クロージャは、単に変数をプライベートにするだけでなく、関数に「状態」を持たせるための強力な手段でもある。関数が呼び出されるたびに新しい状態を作るのではなく、前回の呼び出しの状態を保持し続けることで、より複雑なロジックをシンプルに記述できるようになる。これは、オブジェクト指向プログラミングにおける「プライベートなプロパティ」に似た挙動を実現するものであり、JavaScriptでの高度なプログラミングにおいて不可欠な概念である。システムエンジニアとしてJavaScriptを扱う上で、このスコープとクロージャの理解は、コードの品質と堅牢性を大きく左右する基盤となる知識である。