32

hereで説明したように、関数定義は定義する前に使用できます。しかし、コードのセクションが try ブロックでラップされるとすぐに、これは当てはまりません。

これにより、「Hello world」が表示されます。

hello();
function hello() { alert("Hello world"); }

しかし、これは "ReferenceError: hello is not defined" を表示します:

try {
  hello();
  function hello() { alert("Hello world"); }
} catch (err) {
  alert(err);
}

したがって、関数宣言に関して、try ブロックには明らかに「特別な」何かがあります。この動作を回避する方法はありますか?

4

3 に答える 3

26

Firefox は関数ステートメントを異なる方法で解釈し、明らかに関数宣言の宣言巻き上げを破っています。(名前付き関数/宣言と式についてよく読んでください)

Firefox がステートメントを異なる方法で解釈するのは、次のコードが原因です。

if ( true ) {
    function test(){alert("YAY");}
} else {
    function test(){alert("FAIL");}
}
test(); // should alert FAIL

宣言の巻き上げにより、関数testは常に「失敗」を警告する必要がありますが、Firefox ではそうではありません。上記のコードは実際に Firefox で "YAY" を警告します。これを実現するコードが最終的に宣言の巻き上げを完全に破ったのではないかと思います。

関数宣言が if/else または try/catch ステートメントにある場合、Firefox は関数宣言を var 宣言に変換すると思います。そのようです:

// firefox interpretted code
var test; // hoisted
if (true) {
   test = function(){alert("yay")}
} else {
   test = function(){alert("fail")}
}

Šime Vidas との簡単な議論の後、次の理由により、Firefox の関数宣言の扱いは非標準であると言わざるを得ません。

プロダクション SourceElement:Statement は、アクションを実行せずに関数宣言のために処理されます。
プロダクション SourceElement : ステートメントは次のように評価されます。

  1. ステートメントを評価します。
  2. 結果 (1) を返します。

FunctionDeclaration と Statement の両方が SourceElements であるため、ステートメント (if/else、try/catch) 内に FunctionDeclarations があってはなりません。シメ・ヴィダスにブラウニーをあげよう!

Try/catch は基本的に if/else の別の形式であり、おそらく同じ例外コードを使用します。

于 2010-11-01T14:04:01.047 に答える
5

関数ブロックが前方関数参照を使用してローカル スコープを確立する場合、try ブロックの内容を即時関数でラップすると、その動作が復元されるようです。

これは Firefox、IE、Chrome で動作します:

try {
  (function(){
    hello();
    function hello() { alert("Hello world"); }
  }())
} catch (err) {
  alert(err);
}

もちろん、try-function 内で定義された関数と変数は、即時関数ラッパーがないと、catch ブロックでは表示されなくなります。ただし、これは、try/catch スクリプト ラッピングの可能な回避策です。

于 2010-11-01T14:30:48.583 に答える
1

あなたはいつでもこの方法でそれを行うことができ、両方の世界の長所を得ることができます:

function hello() {
  alert("Hello world");
}

try {
  hello();
}
catch (err) {
  alert(err);
}

引き続きcatchブロックで例外を取得しますが、関数は使用可能になります。メンテナンスも簡単なはずで、とにかく吊り上げ機能に機能的なメリットはありません。

編集:

これがtrycatchでコード全体を包むのと同じくらい耐久性があることを示すために、より詳細な例を提供します。

function hello(str) {
  alert("Hello, " + str);
}

function greet() {
  asdf
}

try {
  var user = "Bob";
  hello(user);
  greet();
  asdf
}
catch (e) {
  alert(e);
}

これは期待どおりに機能し、解析の問題はありません。ロード時に失敗する可能性がある唯一の場所は、関数defsとtrycatchの外側です。また、関数defs内のガベージについても例外が発生します。

これはスタイルの好みだと思いますが、他のオプションよりも読みやすく、保守しやすいようです。

于 2010-11-01T14:47:57.130 に答える