前回は、オブジェクト指向を支援する機能を提供するオブジェクト指向言語であるJavaScriptにおける変数とオブジェクトについてまとめた。ここでは、関数自体の演算である関数と状態を持つ関数であるクロージャについて解説する。
1 関数宣言文と関数リテラル式
関数宣言文と関数リテラル式で関数を宣言できる。関数宣言文で宣言した関数は宣言より前に呼び出し可能である。
2 関数呼び出しの整理
関数呼び出しの分類は以下の通り。
- メソッド呼び出し:レシーバオブジェクト経由での関数呼び出し(applyとcallの呼び出しも含む)
- コンストラクタ呼び出し:new式での関数呼び出し
- 関数呼び出し:上記2つ以外の関数呼び出し
関数宣言文の巻き上げ
関数宣言文で宣言した関数は、宣言した行より前のコードから呼べる。
3 引数とローカル変数
argumentsオブジェクト
関数内でargumentsオブジェクトを使うと実引数にアクセスできる。
再帰関数
再帰関数とは内部で自分自身を呼び出す関数である。このような処理を再帰処理や再帰呼び出しと呼ぶ。再帰関数には再帰処理を停止する条件判定が必須である。これを停止条件と呼ぶ。
4 スコープ
スコープとは名前(変数名や関数名)の有効範囲のことである。JavaScriptのスコープは以下の2つである。
- グローバルスコープ:関数の外(トップレベルコード)のスコープ
- 関数スコープ:関数内で宣言した名前が持つスコープ。その関数内でのみ名前が有効。ローカルスコープやローカル変数ともいう
Webブラウザとスコープ
クライアントサイドJavaScriptでは各ウィンドウ(タブ)、各フレーム(iframe含む)ごとにグローバルスコープがある。
ブロックスコープ
JavaScript(ECMAScript)にはブロックスコープがない。これは他の多くのプログラミング言語と異なる。
letとブロックスコープ
JavaScriptの独自拡張にブロックスコープを使えるletがある。letを使う構文はlet定義(let宣言)、let文、let式の3つがある。
入れ子の関数とスコープ
JavaScriptの関数は入れ子で宣言できる。つまり関数の中で別の関数を宣言できる。内側の関数の中から外側の関数スコープにアクセスできる。
シャドーイング
シャドーイングとは、スコープの小さい同名の変数(や関数)でスコープの大きい名前を隠すことをさす。多くは意図せず起きてバグの元になる。
5 関数はオブジェクト
関数はオブジェクトの1種である。内部的にはFunctionオブジェクトを継承する。これはconstructorプロパティで確認できる。
関数名とデバッグ容易性
関数名は関数オブジェクトの参照を持つ変数名である。
6 Functionクラス
Functionクラスは関数オブジェクトのためのクラスである。
Functionクラスの継承
JavaScriptの関数はFunctionクラスのインスタンスオブジェクトである。プロトタイプ継承の用語を使うとJavaScriptの関数のプロトタイプオブジェクトはFunction.prototypeである。
7 入れ子の関数宣言とクロージャ
クロージャの表層的な理解
クロージャ(closure)を表層的に理解すると、状態を持つ関数である。
クロージャの仕組み
- 入れ子の関数宣言:関数宣言の中に別の関数宣言を書けること
- 入れ子の関数とスコープ
- 入れ子の関数を返す
- クロージャ
- クロージャと環境:関数呼び出し時点における変数名解決の環境を保持した関数
クロージャの落とし穴
関数f内に2つの関数宣言があると、2つは同じCall-fオブジェクトを参照するという落とし穴がある。
名前空間の汚染を防ぐ
- モジュール:JavaScriptの言語仕様にはこれを持たない
- グローバル変数の回避:オブジェクトリテラルで生成したオブジェクトのプロパティにして名前をオブジェクトの中に閉じ込めると(形式的に)グローバル変数が減る
- クロージャによる情報隠蔽
クロージャとクラス
コンストラクタ版のクラスには、プロパティ値のアクセス制御(privateやpublicなど)ができないという課題がある。
8 コールバックパターン
コールバックと制御の反転
コールバックとは、呼んでほしい関数やオブジェクトを渡しておき、必要に応じてそれらを呼んでもらう技法である。呼ぶ側と呼ばれる側の依存性が反転することから制御の反転(IoC:Inversion of Control)と呼ぶこともある。
JavaScriptとコールバック
- コールバック関数
- コールバックとメソッド
- クロージャとコールバック
最後に
手続きをまとめる目的で関数を使えるが、それだけではJavaScriptの言語の力を使っているとは言えない。関数自体を演算対象にすることとクロージャを理解することで、関数型プログラミングを活用することができるのである。
次回は、配列、JSON処理、日付処理、正規表現など JavaScriptのデータ処理について解説する。
![]() |