『JavaScript Ninjaの極意』を読んでいて気になったこと。予めことわっておきますが、書評とかそういうのではありません。
「3.2.1 スコープと関数」で、JavaScriptの変数と関数のスコープについて解説されているのですが、これは間違いなのではないでしょうかと。例として次のようなコード片で解説されております。
function outer() { var a = 1; function inner() {} var b = 2; if (a == 1) { var c = 3; } } outer();
このコード例に対して、次のようなテストを上記コード例の各ステップに挿入して実行します。
assert(true, "何らかの記述的なテキスト"); assert(typeof outer==='function', "outer()はスコープ内にある"); assert(typeof inner==='function', "inner()はスコープ内にある"); assert(typeof a==='number', "aはスコープ内にある"); assert(typeof b==='number', "bはスコープ内にある"); assert(typeof c==='number', "cはスコープ内にある");
そして実行結果を挙げ、次のように解説されております。
・bのスコープは、4行目〜7行目の範囲 ・cのスコープは、6行目〜7行目の範囲 ※実際の解説は、同書p.49以降の本文および「図3-6」として記述されております。
簡単に言ってしまいますと、同書では関数宣言はホイスティングされるが変数宣言はされないとおっしゃっております。いえいえ、何か重箱のスミを突っつくようなつまらないことではありますが、関数内で宣言された変数のスコープは、その変数宣言を含む関数内全域なのではないでしょうか。試しに1行目と2行目の間辺りに、「c = 9;」とでも置いてみればわかります。
function outer() { c = 9; var a = 1; function inner() {} var b = 2; if (a == 1) { var c = 3; } } outer();
もし、2行目で変数cがスコープ外なのであれば、ここのcによって参照されるのはouterの外にあるcということになりますが、そうはなりません。これは7行目で宣言される変数cに対する代入となります(つまりホイスティングされる)。JavaScriptでは、変数の宣言と代入とは同時に記述されていたとしても、あくまで別々に実行されます。これは、変数や関数の宣言はコンパイル時に、代入などの式(なので関数式も同様です)や制御文は実行時に評価・実行される、というところからくる振る舞いです。こういった訳で、outer関数冒頭ではまだ宣言されていないはずのcに対して代入が出来てしまうのですね。したがって、同書のこの箇所に限っては誤りでしょう。この辺りの解説は、『JavaScript 第6版』が参考になるのではないでしょうか。
あと、フォローしておきますが、<a href="http://www.amazon try this out.co.jp/JavaScript-Ninja%E3%81%AE%E6%A5%B5%E6%84%8F-%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E9%96%8B%E7%99%BA%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E7%9F%A5%E8%AD%98%E3%81%A8%E3%82%B3%E3%83%BC%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0-Programmers%E2%80%99-SELECTION/dp/4798128457/ref=sr_1_1?s=books&ie=UTF8&qid=1370685086&sr=1-1&keywords=JavaScript+ninja”>『JavaScript Ninjaの極意』は素晴らしい本ですよ。御勘違いなく。