まめージェント

Android, GAE, AngularJSの技術ネタ中心。Twitter: @mame01112

JavaScriptのホイスティングについて調べてみた

JavaScriptにはどうやら、"ホイスティング (hoisting)"なる仕様があるらしいので、今回はそれを勉強した結果をまとめてみようと思います。

ホイスティングとは?

ホイスティングは"hosting"と書くようです。英語で"hoist"は揚げる、持ち上げる、つり上げる、巻き上げるなどの意味があるようです。日常会話じゃ使わない英語だなぁ。。。
JavaScript的に言えば、"JavaScriptは関数内のどこでもvarで変数宣言をすることができるが、それらの変数は、どこで宣言したとしても、常に関数の一番戦闘で宣言されたように動作する"ということのようです。

つまり、

(function(){
	console.log("a: " + a);
	var a = 1;
})();

というコードであれば、

(function(){
    var a;
	console.log("a: " + a);	// Undefined
	a = 1;
})();

ということになり、console.logで使っている時点ではaの変数はundefinedになるということになりますね。
上記くらいシンプルな例だったら分かりやすいですが、これが複雑になってくると、いろいろと不具合も起きそうです。ちょっとググっただけでも、
・「変数は常に関数の先頭で宣言するようにしましょう」
・「ホイスティングは絶対にさせるべきではない」
・「ホイステイングが原因になる不具合を避けるために、coffee-scriptを使いましょう」
という内容がみつかりました。

何か非常に問題児扱いされているホイスティング、何故JavaScriptがこんな仕様になっているか、調べてみました。

何故ホイスティングって仕様が存在するのか?

・http://stackoverflow.com/questions/15005098/why-does-javascript-hoist-variables
 ーホイスティングはJavaScriptのインタプリタの仕様のため。
 ーJavaScriptのコードの解釈(interpretation)は2つの方法がある
  ーStep 1: varあり変数(declared variable)と関数文(Function declaration)を解釈する
  ーStep 2: 解釈した関数式(Function expression)とvarなし変数(undeclared variable)を解釈(process)し、コードを実行する。
 ー上記2つのステップのためにホイスティングは存在する

つまり、スコープが先に決まるものを先に実行解釈し、その後にスコープが実行時の状況に応じて変わるものを解釈、実行するわけですね。まあ、考えてみればそりゃそうですね。

なので、ホイスティングは、

(function(){
	console.log("a: " + a);
	var a = 1;
})();

のconsole.log("a: " + a);のaって何モノ?(=どのScopeのaなの?)を知るために、

(function(){
	var a;
	console.log("a: " + a);
    a = 1;
})();

というように解釈することで、どのaを参照するか?を決めるために使われる言語仕様、ということができるでしょうか。
※この場合は出てきていないですが、同じaという名前の変数が、グローバルにもある可能性がありますからね。

現状、いろいろと記事を読みながら僕が理解したホイスティングです。
もち間違っていればご指摘くださいませ〜。