4

次のコードを検討してください。

<!DOCTYPE html>
<script>
  console.log(a);
  function a() {}
</script>

aが定義される前にアクセスされているように見えることに注意してください。コンソール出力は次のとおりです: ( jsfiddle )

function a() {}

関数名と変数名は他のコードが実行される前に定義されるため、console.log 呼び出しはここで機能します。これを巻き上げといいます。

ただし、関数が関数呼び出しでパラメーターとして定義されている場合、これは機能しません。このコードを見てください。

<!DOCTYPE html>
<script>
  function a() {}
  a(function b() {});
  console.log(b);
</script>

b関数が への呼び出し内で定義されていることに注意してくださいa。クロージャーの内部ではなく、呼び出しの内部。コンソール出力は次のとおりです: ( jsfiddle )

Uncaught ReferenceError: b is not defined

なぜこれが起こるのか疑問に思っています。これは意図した動作ですか?これは、Chrome と Firefox の両方で発生します。

更新:このjsfiddleは、関数式の名前が、それらが定義されているスコープでは使用できないことを示しています。ただし、名前は関数自体のスコープ内で定義されます。つまり、名前付き関数式は名前を参照できますが、関数内でのみ参照できます。name名前は、関数のパラメーターにも格納されます。

<!DOCTYPE html>
<script>
  console.log(a); // undefined
  var a = function b() {
    console.log(b); // function b() { … };
  };
  a(); // function b() { … };
  console.log(a); // function b() { … };
  console.log(a.name); // b
  console.log(b); // Uncaught ReferenceError: b is not defined
</script>
4

3 に答える 3

3

EcmaScript §13 ( NOTEの下の段落を参照) は、関数式と関数宣言の処理方法を定義しています。

関数宣言は、EnvironmentRecord の構築時 ( §10.5 ) にインスタンス化されるため、ホイストされます。関数式は後で評価され、オプションの Identifier は囲んでいるスコープには表示されません。

これは関数式であるため、その名前は外側のスコープからは見えません。まるで同じです

a = function(){};  // valid as it is a function expression

a = function b(){};// also valid

// b is is not accessable here, same as the anonymous function, but a of course is.

どちらも有効ですが、b は外側のスコープからは見えません。ただし、関数宣言で名前を省略することは無効です。
関数式のオプションの Identifier は、関数本体内で参照するためのものです (たとえば、再帰呼び出しを有効にするため)。

あなたの更新に更新します。

最初の console.log がエラーをスローする代わりに undefined を生成する理由は、ホイストです (インスタンス化がホイストされている間、初期化はホイストされていません):

  console.log(a); // undefined
  var a = function b() {};
  console.log(a); // function b() {}

  // equals (hoisted):
  var a;
  console.log(a); // undefined
  a = function b() {};
  console.log(a); // function b() {}
于 2013-01-08T15:51:20.220 に答える
3

内部a(function b() {});では、関数は関数式であり、関数宣言ではありません(ホイストされているもののみ)。違いについては、var functionName = function() {} vs function functionName() {}をご覧ください。

于 2013-01-08T15:50:15.567 に答える
0

function b()a(function b() {});呼び出しが実行されるまで存在しません。

そのように、JS は関数のコードを検索しません。また、function b() {}関数宣言ではありません。単にパラメーターとして渡しているだけです。その関数にアクセスする唯一の方法は次のfunction a()とおりです。

function a() {console.log(arguments[0])}
a(function b() {});
//function b() {}

ただし、関数自体ではなく、 の関数呼び出しのスコープで定義されているため、これは実際にb()内部a()で呼び出すことができるという意味ではありません。基本的に、名前は役に立ちません。b()ab

于 2013-01-08T15:49:09.233 に答える