tanaka's Programming Memo

プログラミングについてのメモ。

パーフェクトJavaScript勉強メモ(6)

前へ | 次へ

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では、タブやフレームごとにグローバルスコープがある
  • ウィンドウ間でのグローバルスコープの相互アクセスは不可
  • フレームは、親との間で相互アクセス可能
ブロックスコープ
letとブロックスコープ
入れ子の関数とスコープ
  • p167 関数の中で関数を定義できる
  • 関数内関数から、外の変数にアクセスできる。内側から外側に、グローバルスコープまで検索する
シャドーイング

関数はオブジェクト

  • JavaScriptの関数は、Functionクラスを継承したオブジェクト
  • p169 関数にプロパティを追加可能
関数名とデバッグ容易性
  • p170 関数はオブジェクトなので正式には名前がない
  • 関数呼び出しに対応するため、表示名は存在する。functionの次に続ける名前は、関数が埋め込んで記録している
  • 関数オブジェクトをprintなどで表示する際に、表示名が使われる
  • 関数リテラル式を使う場合、関数名は省略できるが、つけておくとデバッグの時に表示されるので便利な場合があるので、利用を検討するとよい

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
Functionクラスの継承
  • p172 関数は、Functionクラスのインスタンスオブジェクトなので、prototypeはFunction.prototypeが該当する
  • Function関数も、Functionクラスのインスタンスオブジェクト

入れ子の関数宣言とクロージャ

クロージャの表層的な理解
  • p173 状態を持つ関数。あるいは、関数を抜けた後も有効なローカル変数
クロージャの仕組み
  • 入れ子の関数で実現
  • p174 関数は呼ばれると、Callオブジェクトというものが暗黙に生成されて関数を実行。実行が終わると自動的に消滅する
  • 内側の関数を実行せずに、オブジェクトをreturnさせる
  • returnさせたオブジェクトインスタンスを変数に書き込んで、実行すると、内側の関数が持っている外側のオブジェクトの参照も生きているので、メモリ解放が発生せず、変数が生き残る
  • p177 クロージャとは、変数名解決の環境を保持した関数のこと。これにより、個別に値を保持し続けることができる
  • 外側の関数内にローカル変数を定義し、その変数にアクセスする関数をリテラル式でreturnするのがクロージャを生成するイディオム
クロージャの落とし穴
  • 関数内に、複数の関数を用意して、それぞれをクロージャとして返した場合、それぞれの関数呼び出しで参照するCallオブジェクトは同一なので、値が共有される
名前空間の汚染を防ぐ
  • p178 モジュール
    • JavaScriptでは、1つのHTMLに複数JavaScriptファイルを読み込んで、様々なライブラリを組み合わせて使うことがある。この時、グローバルオブジェクトは共有されるため、グローバルオブジェクトへのプロパティの追加は避けたい
  • グローバル変数の回避
    • p179 自分のプログラム用のグローバルオブジェクトを1つ用意して、関数と変数を全てそのプロパティに入れる
    • しかし、この方法では、外部からプロパティの書き換えができてしまう
  • p180 クロージャによる情報隠蔽のためのイディオム
(function() {関数本体})();
  • 公開するメソッドとプロパティのリストのオブジェクトを、オブジェクトリテラルでreturnする

クロージャとクラス

  • p181 インスタンスを生成する関数を用意する方法
  • p182 内部で値を保持する例
  • thisをreturnしておくと、メソッドチェインで便利

コールバックパターン

コールバックと制御の反転
  • 呼び出して欲しいものを渡しておいて、必要に応じて呼び出してもらうこと。相手から呼び出してもらうので制御の反転(IoC:Inversion of Control)と呼ぶことも
JavaScriptとコールバック
  • p183 コールバックの解説
  • コールバックとメソッド
  • p185 コールバックする際にthisを正しく解決する方法
    • bindを利用する。ECMAScript5から実装。callとapplyでも実現可。通常はこちらを使う。コールバックを登録する際に、bindでthisを指定して新しく生成した関数を渡す
    • オブジェクトを登録する
  • クロージャとコールバック

前へ | 次へ