m2

ちょっと勘違いしてた function a() と var a = function() の違い(JavaScriptのスコープの話)

両者は等価だと思ってたんだけど、実際はちょっと違うみたい。

改行付き

javascript:(
function(){
    function a(){
        alert('a')
    }
    if(false){ 
        function a(){
            alert('b')
        }
    }
    a();
})()

予想に反して 'b' が表示されてしまった。
じゃあ window.a が定義されたのかと思ったらこれも違っていて undefined。if 文とか関係無しに function hoge() は、宣言した function 内で全て有効な感じ。
これを避けたいなら var a = function() にする。

javascript:(
function(){
    var a = function(){
        alert('a')
    };
    if(false){ 
        var a = function(){
            alert('b')
        };
    }
    a();
})()
  • -

説明不足だったので追記。
後者の場合は 1.無名関数を定義して 2.それを a に代入している。2 の代入の部分が if 文の制御下にあるので違いが起きる。

  • -

var のスコープについても誤解してた。上の例で if 内でエラー無しに var 宣言できるけど、if 内だけで有効な変数という訳ではなくて function 内の a を上書きする。Java なんかだとコンパイルエラーになるからわかるけど JavaScript では一見問題なさそうに見えるから見逃しがしがち。例えば以下。

javascript:(function(){ var i=100; for(var i=0; i<10; i++){ void(0); } alert(i); })()
  • -

そこで勇者 FireFox

  • -
JavaScriptブロックスコープを実現する: Days on the Moon
http://nanto.asablo.jp/blog/2006/07/08/437419

with かぁ。

  • -

コメントにて、このエントリで問題にしていることそのものについて解説しているページを教えていただきました。感謝! (つーか上と同じ「Days on the Moon」だわ。)

Function Expression Statements: Days on the Moon
http://nanto.asablo.jp/blog/2005/12/10/172622

なるほど、僕が等価だと勘違いしていたものは文法上正式に異なるものなんですね。

FunctionDeclaration
普通の関数宣言。プログラム直下か function 直下にしか書けない。
(function(){
  function a(){
    alert('hoge');
  }
  a();
})()
FunctionExpression:
上の例で function 名を書いてない(変数に代入している)ヤツ。名前を書くこともできるけどその function の中からしか参照できない(←初めて知った)。
(function(){
  var b
  if (true) b = function a(){alert(a)};
  b(); // a() では呼び出せない
})()
FunctionStatement(仮)
上の例で function 名を書いている(変数に代入してない)ヤツ。JavaScript(Firefox) では有効だけど ECMAScript としては文法違反。が、IE(JScript) や Opera だと FunctionDeclaration っぽく振舞う。
(function(){
  if (true) function a(){alert(a)};
  a();
})()

つくづく僕がやってることって2〜3年遅れてると思った。最も誤解さえしていなければもう少し縮まってたかなあ?