55

関数宣言はどのように処理されますか?

var abc = '';
if (1 === 0) {
  function a() {
    abc = 7;
  }
} else if ('a' === 'a') {
  function a() {
    abc = 19;
  }
} else if ('foo' === 'bar') {
  function a() {
    abc = 'foo';
  }
}
a();
document.write(abc); //writes "foo" even though 'foo' !== 'bar'

この例では、Chrome と Firefox で異なる出力が生成されます。Chrome は出力fooし、FF は出力します19

4

4 に答える 4

71

この質問がされたとき、ECMAScript 5 (ES5) が普及していました。ifES5 の厳密モードでは、質問に示されているように、関数宣言をブロック内にネストすることはできません。非厳密モードでは、結果は予測できませんでした。さまざまなブラウザやエンジンが、ブロック内の関数宣言を処理する方法について独自のルールを実装していました。

2018 年現在、多くのブラウザーが ECMAScript 2015 (ES2015) をサポートしており、ブロック内で関数宣言が許可されるようになりました。ES2015 環境では、ブロック内の関数宣言はそのブロック内にスコープされます。a関数はステートメントのスコープ内でのみ宣言されているifため、グローバルスコープには存在しないため、問題のコードは未定義関数エラーになります。

関数を条件付きで定義する必要がある場合は、関数式を使用する必要があります。

于 2012-04-09T05:51:06.213 に答える
7

http://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/から

JavaScriptでは、関数宣言があります:

function foo() {
}

と関数式

var foo = function() {
}

http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoistingからの引用

「関数宣言と関数変数は、常に JavaScript インタープリターによって JavaScript スコープの先頭に移動 (「ホイスト」) されます。

したがって、最初の例で起こったことは、の関数宣言がfunction a()Javascriptスコープの一番上に持ち上げられ、ifがfalseと評価されても「foo」を生成することです

var foo通常の Javascript ステートメントと考えてください。 とは異なりfunction foo()、JavaScript のランタイムでのみ実行されます。そのため、以下が有効です。

alert(foo());

function foo() {
   return 'gw ganteng';
}

ここでfunction foo()は、呼び出しを試みる前に、パーサーによって解析されfoo()、現在のスコープに入れられますalert(foo())

http://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/

JavaScript の実行には、Context (ECMA 5 が LexicalEnvironment、VariableEnvironment、および ThisBinding に分割する) と Process (一連のステートメントが順番に呼び出される) があります。実行スコープに入ると、宣言は VariableEnvironment に寄与します。それらはステートメント (返品など) とは異なり、プロセスのルールの対象ではありません。

于 2012-04-09T05:29:02.247 に答える
2

ECMA-262 v5 では、新しいグローバルまたは関数レベルの実行コンテキストに入るときに、最初のパス中にすべての関数と変数の宣言を登録する実装が必要です。Chrome は実行前にelseandthenブロック内を調べて登録するため、技術的にはここでそれを行っています。a()残念ながら、それは最も読みにくい結果をもたらします。

FF は、関数と変数の宣言を評価して現在のコンテキストに追加する前に、if ステートメントを評価するまで待機しています。ところで。どちらのブラウザも、catch 句と finally 句の中でこの方法を実行します。

そもそも存在すべきではない機能を扱うのは、実際には 2 つの異なる ECMA 実装の問題です。目の前のシナリオは、関数宣言が制御フロー ステートメント内にあってはならない理由を示しています。

于 2013-12-11T23:42:16.930 に答える
0

{}関数宣言は、ブロック外ではアクセスできません。

if (true) {
  function sayHi() {
    alert("hii");
  }
  sayHi(); //accessible
}

sayHi(); //error, not accessible since out of the block

条件付き関数を定義する場合は、次のような関数式を使用します

let sayHi;
if (true) {
  sayHi = function(){
    alert("hii");
  }
  sayHi(); //accessible
}

sayHi(); //accessible
于 2021-02-05T02:50:22.063 に答える