[Javascript] 関数宣言の落とし穴 function foo ( ){..} と var foo = function ( ) {..} は動作が違うので要注意!

function funcname(args){ do something};

は

var funcname = function(args){ do something};

と等価になる。
javascriptを理解するためのたった2つの大切なこと
javascriptを理解するためのたった2つの大切なこと:改

引用元の記事はすばらしい記事ですが、ここは間違いです。
等価だと思っていたらひどい目にあいます。
サイ本 第5版のp.96にちゃんと書いてあります。
function文はプログラムの静的な構造を定義するだけなのです。
JavaScriptコードが解析されコンパイルされたときに、関数は定義されます。

どういうことかというと、
function foo( ){ ... }
コンパイル時に関数が定義されます。

var foo = function( ){ ... };
代入文の実行時に関数が定義されます。

その証拠に、
foo();
function foo(){ alert(1) }
はOKですが、

foo(); // エラー
var foo = function (){ alert(1) };
はエラーになります。

ささいな違いに見えますが、プロトタイプを使うときは要注意です。
プロトタイプを使ったメソッド定義は必ず代入文だからです。

メソッド定義は代入文!!

FireFoxでは下記のようなメソッド定義をしようとすると、何故かエラーになります。(IEでは動きます)
function Foo(){  }; // クラス宣言
function Foo.prototype.greet(){ alert('hi') }; // エラー
従って、メソッド定義は代入文で書くことになります。
function Foo(){  }; // クラス宣言
Foo.prototype.greet = function (){ alert('hi') }; // メソッド定義は代入文で

正常に動作するケース

よって、下記のコードは動きます。
function Foo(){  };
Foo.prototype.greet = function (){ alert('hi') };

var foo = new Foo();
foo.greet();

これも動きます。
Foo.prototype.greet = function (){ alert('hi') };
function Foo(){  };

var foo = new Foo();
foo.greet();

こんなのもOKです。
Foo.prototype.greet = function (){ alert('hi') };

var foo = new Foo();
foo.greet();

function Foo(){  };

こんなんだって動いちゃいます。
var foo = new Foo();

Foo.prototype.greet = function (){ alert('hi') };

foo.greet();

function Foo(){  };

エラーになるケース

これはエラーです。
var foo = new Foo();
foo.greet();

function Foo(){  };
Foo.prototype.greet = function (){ alert('hi') };

これもエラーです。
var foo = new Foo();
foo.greet();

Foo.prototype.greet = function (){ alert('hi') };
function Foo(){  };
おわかりでしょうか?

まとめ

  • function foo ( ){..} と var foo = function ( ) {..} は、関数が生成されるタイミングが違う
  • プロトタイプによるメソッドの宣言は、代入文である。
  • メソッドの代入は、
     クラス宣言をした後、かつ、インスタンスからメソッド呼び出しをする前
    にやるべし。

カテゴリ: