6章 関数とクロージャ
p159 関数宣言文(function 関数名(引数リスト){})と関数リテラル式(function (引数リスト){})
関数呼び出しの整理
- メソッド呼び出し…オブジェクトから呼び出す。呼び出し元のオブジェクトの参照をthisに持つ。applyやcallでは任意のオブジェクト
- コンストラクタ呼び出し…オブジェクトを生成して、関数内の処理を実行。thisは生成されたオブジェクトへの参照
- 関数呼び出し…グローバルオブジェクトをthisとして実行
関数宣言文の巻き上げ
- p160 関数宣言文で宣言した関数は、宣言より前の行から呼び出すことができる
- 関数リテラル式で宣言した関数は、宣言より前の行からは呼び出せない
引数とローカル変数
argumentsオブジェクト
- 引数の取り出しに使える。これを利用すると、関数宣言の()内に引数リストをつけなくてもよい
- p161 argumentsオブジェクトは配列ではない
再帰関数
- JavaScriptの無限ループは実装依存
- 再帰関数は、ループに置き換えることが可能
- JavaScriptの再帰は効率がよくないので、避けられるなら避けておく
- arguments.calleeで、実行中の関数オブジェクトへの参照が得られる。無名関数で再帰を行う時に利用できる(ECMAScript5のstrict modeではcalleeは無効)
スコープ
- グローバルスコープと関数スコープの2つがある
- 関数内では、var宣言の前でも変数は有効となるので、グローバルにアクセスにいかない。紛らわしさを避けるため、ローカル変数の宣言は関数の先頭で行う
Webブラウザとスコープ
- p163 クライアントサイドJavaScriptでは、タブやフレームごとにグローバルスコープがある
- ウィンドウ間でのグローバルスコープの相互アクセスは不可
- フレームは、親との間で相互アクセス可能
ブロックスコープ
- JavaScriptにはブロックスコープはない
- p164 for文でもブロックスコープは無効なので注意
letとブロックスコープ
- JavaScript独自拡張でletによるブロックスコープがある
入れ子の関数とスコープ
- p167 関数の中で関数を定義できる
- 関数内関数から、外の変数にアクセスできる。内側から外側に、グローバルスコープまで検索する
関数はオブジェクト
- JavaScriptの関数は、Functionクラスを継承したオブジェクト
- p169 関数にプロパティを追加可能
Functionクラス
- Functionクラスの関数呼び出しやnewで関数の生成ができる。が、通常はfunctionで宣言すればよい
- p171 Functionのプロパティは、prototypeとlength
- Function.prototypeのプロパティは以下の通り
- apply
- bind(実行時にthisに入れるオブジェクト[,引数1,引数2,・・・])…新しい関数オブジェクトを返す。その関数を呼ぶと、第1引数をthisに入れた状態で、引数を指定して関数が実行される
- call
- callee
- constructor
- isGenerator(JavaScript独自拡張)
- length…関数の仮引数の数
- name(JavaScript独自拡張)…関数の表示名
- toSource(JavaScript独自拡張)
- toString()
- Functionのインスタンスプロパティ
- callee
- length
- name(JavaScript独自拡張)
- prototype
入れ子の関数宣言とクロージャ
クロージャの表層的な理解
- p173 状態を持つ関数。あるいは、関数を抜けた後も有効なローカル変数
クロージャの仕組み
- 入れ子の関数で実現
- p174 関数は呼ばれると、Callオブジェクトというものが暗黙に生成されて関数を実行。実行が終わると自動的に消滅する
- 内側の関数を実行せずに、オブジェクトをreturnさせる
- returnさせたオブジェクトインスタンスを変数に書き込んで、実行すると、内側の関数が持っている外側のオブジェクトの参照も生きているので、メモリ解放が発生せず、変数が生き残る
- p177 クロージャとは、変数名解決の環境を保持した関数のこと。これにより、個別に値を保持し続けることができる
- 外側の関数内にローカル変数を定義し、その変数にアクセスする関数をリテラル式でreturnするのがクロージャを生成するイディオム
名前空間の汚染を防ぐ
- p178 モジュール
- JavaScriptでは、1つのHTMLに複数のJavaScriptファイルを読み込んで、様々なライブラリを組み合わせて使うことがある。この時、グローバルオブジェクトは共有されるため、グローバルオブジェクトへのプロパティの追加は避けたい
- グローバル変数の回避
- p179 自分のプログラム用のグローバルオブジェクトを1つ用意して、関数と変数を全てそのプロパティに入れる
- しかし、この方法では、外部からプロパティの書き換えができてしまう
- p180 クロージャによる情報隠蔽のためのイディオム
(function() {関数本体})();
コールバックパターン
コールバックと制御の反転
- 呼び出して欲しいものを渡しておいて、必要に応じて呼び出してもらうこと。相手から呼び出してもらうので制御の反転(IoC:Inversion of Control)と呼ぶことも