JSLintとJSHintとhoisting

↓こんな記事を発見。(私がJSLintをフォークしてJSHintを作った理由)
http://anton.kovalyov.net/2011/02/20/why-i-forked-jslint-to-jshint/

ここで話題になってるJSLintを作った人が、今読んでるJavaScript:Good Partsの著者らしいのでちょっと興味が沸いて読んでみた。

JSLint でのチェックができない!

よくあるコードだと思うんですが↓のようなコードをJSLintすると

var myfunc = function() {
	for ( var i = 0; i < 3; i++  ) {
		/* something */
	}
};

↓こんなふうに言われてそれ以降のチェックが行われない。

Error:
Problem at line 2 character 11: Move 'var' declarations to the top of the function.
for ( var i = 0; i < 3; i++ ) {

「varによる定義はfunctionの先頭に持っていくべし」とのこと。

"JSLint can NOT suck it"

ブログの著者が言うには

これを見逃すようにするなオプションはないのでコードを書き換えるかJSLint使うのやめるかしかない。
このエラー&チェック停止はjsコミュニティでも歓迎されていないっぽい。
→ Crockford氏(JSLint作者)駆動ではなく、コミュニティ駆動開発のツールを作ろう
→ JSHint

ということになったらしい。

JSLintが "for(var ..." に文句を言う理由

ブログのコメントをみるとvarを上に持っていけというのにはちゃんと理由があるらしい。

'hoisting'というものがあって・・・
varをfunctionの一番上に持っていかないと発見しづらい問題を起こすことがある。

hoistingってなに?

var foo = 'bar';
(function(){
    if(false){
        var foo = 'BAZ';
    }
    alert(foo);    // bar でも BAZ でもなく... undefined !
})();

↑のコードを実行すると"undefined"とアラートが出る。

         ,. -‐'''''""¨¨¨ヽ
         (.___,,,... -ァァフ|       あ…ありのまま 
          |i i|    }! }} //|      今 起こった事を話すぜ!
         |l、{   j} /,,ィ//|
        i|:!ヾ、_ノ/ u {:}//ヘ     『グローバル変数を参照したと
        |リ u' }  ,ノ _,!V,ハ |     思ったら消えていた』
       /´fト、_{ル{,ィ'eラ , タ人 
     /'   ヾ|宀| {´,)⌒`/ |<ヽトiゝ
    ,゙  / )ヽ iLレ  u' | | ヾlトハ〉
     |/_/  ハ !ニ⊇ '/:}  V:::::ヽ 
    // 二二二7'T'' /u' __ /:::::::/`ヽ
   /'´r -―一ァ‐゙T´ '"´ /::::/-‐  \  
   / //   广¨´  /'   /:::::/´ ̄`ヽ ⌒ヽ 
  ノ ' /  ノ:::::`ー-、___/::::://       ヽ  }
_/`丶 /:::::::::::::::::::::::::: ̄`ー-{:::...       イ 

これは

  • alert時のfooは一番近いスコープ(ここでは関数内)のfooを参照しようとする
    • ↑つまり var foo = 'BAZ';
  • このためグローバルにあるfoo(barのほう)は関数内では参照されない
  • でもalertの実行時にはvar foo = 'BAZ';は実行されていない
  • undefined

っていうことらしい

ぶひー。確かにこれのせいで問題が起こってもなかなか見つからなそう・・・
でも

// こういう習慣を
for(var i = 0; i < 3; i++)

// こう変えなさい
var i;
for(i = 0; i < 3; i+=1)

と、急に言われても困るというのはある。。