2011-09-07 11 views
5

コードは単純です:、この動作の説明は何ですか? (ときの機能が作成された?)問題の

console.log("So it begins."); 
foo(); 
function foo() { console.log("In foo()."); } 
console.log("So it ends."); 

なぜfoo()が実行さん、それが定義される前に(遡及的な編集を:ChromeとSafariで)?

私はクロム、SafariやFirefoxで次のコードをテストし、これに少し手を加え:

javascript:foo();function foo() { alert("Oh."); } 

Firefoxは沈黙したままアラートが、ChromeとSafariで表示されます。

この驚くべき、一貫性のない動作の説明はありますか?

+0

コンソール出力とは何ですか? – wosis

答えて

3

(私は個人的にそれを呼び出す見つけるを巻き上げより前処理より明確なコンテキスト準備)のFirefoxの異なる振る舞いの理由は未解決のまま。

まず、関数宣言と関数文の違いを知っておく必要があります。

関数の宣言、あなたの例のように、たとえば、グローバルコード内(関数の外側)と直接別の関数の関数の本体内で、2つのだけの場所で発生する可能性があります:

function foo() {} 

function bar() { 
    function baz() {} 
} 

すべて上記の関数は有効な関数宣言です。

ECMAScriptの仕様は、ブロック内の例えば他の場所で関数宣言を定義することはできません:

if (true) { 
    function foo() {} 
} 

上記の機能をはあなたにSyntaxError例外を与える必要がありますが、ほとんどの実装は善意であり、彼ら実際の機能に到達できない場合でも(例えばif (false) { function bar() {} })、機能を前処理(ホイスト)します。 Firefoxので

、制御は、例えば、その特定のステートメントに達したときに関数定義が実際に起こることを意味が許可されているファンクション文、:Firefoxで、上記の文の後にfoo();を実行

if (true) { 
    function foo() { return true; } 
} else { 
    function foo() { return false; } 
} 

が生成されますtrueifステートメントの最初の分岐が実際に実行されるためです。すべての機能が前処理された実行コンテキストを入力するときであるため、他のブラウザで

foo();falseを生成し、最後のものはif文のfalse分岐がに達したことがない場合でも、優先されます。

ブロックはtry-catchブロック内にコードをラップして実行します。そのため、機能は利用できません。の前には、の宣言があります。

コンソールにしようとした場合:

console.log(typeof f); // "undefined" 
function f() {} 

あなたはfがまだ用意されていないことがわかりますが、あなたが関数内のコードをラップする場合は、予想される動作が表示されます。

(function() { 
    console.log(typeof f); // "function" 
    function f() {} 
})(); 

これもまた、fが関数宣言として定義されているのは、匿名関数の本体に存在し、ステートメントブロックの一部ではないからです。

+0

これを破るに入れて努力をいただきありがとう、それを感謝します。 – maligree

8

JavaScriptの破棄は常に先頭に移動されます。それはを巻き上げと呼ばれています:

例: http://jsbin.com/abelus/edit

+2

まずは、ありがとう。第2に、いいえ、それはすべてのブラウザで同じように動作しません - 少なくとも、書き込みの時点では。 Firefox 6.0.2でリンクしたサンプルコードをテストしましたが、「hello」は表示されません。 – maligree

+0

@maligree、それは本当に私を驚かせた。この例はFirefox 6で動作します:http://jsbin.com/abelus/2/edit。これはjsbinの問題です。 jsFiddle works:http://jsfiddle.net/vVhAc/ – binarious

3

気づいている動作はfunction hoistingと呼ばれます。

簡潔に言えば、function foo() { ... }という構文を使用して定義された関数は、定義されているスコープの先頭に "吊り上げ"られるため、定義する前に呼び出すことができます。

これは、JavaScriptのあいまいな部分です。ブラウザの実装方法に違いがある場合(特に古いバージョンのFirefoxを使用している場合)は、私には驚かないでしょう。他は機能の「巻き上げ」の動作を説明しながら

+0

吊り上げのための+1、例のための-1;実行時に 'bar()'と 'foo()'の存在が検出されるため(例えば 'bar'と' foo'関数を呼び出すときに)再帰が機能します。 – Matt

+0

@Matt、あなたが正しい。私は例を削除すると思う:) – riwalk

関連する問題