4

私はJSライブラリのコードを調べていて、このパターンを見ました:

function module() {
    function func() {
        //...
        definedAfter();
        //...
    }
    return func;
    var x = "....";
    function definedAfter() {
        //...
        console.log(x); //outputs undefined
        //...
    }
}

Google の Closure コンパイラは変数に未使用コードとしてフラグを立てxますが、これは妥当なようですが、興味深いのは、変数が宣言されていますが、値がundefined(ホイストによる) であるということです。

これはライブラリのバグですか?それとも、ここで悪用されている微妙な動作はありますか? 多分ある種の最適化?この例に関して、ブラウザーが異なれば動作も異なりますか?

編集: 元のコードの意図 (バグまたはその他) に興味がxありますundefined

4

3 に答える 3

3

巻き上げについては理解していると思いますが、機能が技術的にどのように見えるかについての説明は次のとおりです。

function module() {
    function func() {
        //...
        definedAfter();
        //...
    }
    function definedAfter() {
        //...
        console.log(x); //outputs undefined
        //...
    }
    var x;
    return func;
    x = "....";
}

(吊り上げられたものの実際の最終的な順序はわかりませんが、重要ではないと思います)

したがって、最後のx = "....";行は実行されることはありませんが、x(as として) 宣言undefinedされ、内部関数スコープからアクセスできます。

xしたがって、「....」として設定された行に決して到達せず、何もしないという意味で、ライブラリには「バグ」があると言わざるを得ません。

于 2013-04-15T16:34:41.800 に答える
1

Benn Flynn のコメントに沿って、パーサーは実際に実行される前にコードを事前スキャンおよび/またはコンパイルします。したがって、ブロック内の実行されているかどうかに関係なく、任意の行から変数のスコープを検出します。

ブラウザのコンソールでこれを実行します。

var f = function() {
  // we haven't defined a local x yet, so we're tempted to think
  // that this line is mucking with window.x
  x = 1;
  console.log(x, window.x);
  return;

  // and we're tempted to think this line is never seen, because it
  // occurs after the return. but, it ensures that x is local, not global.
  var x = 2;
};
f();

コンソールに次のように表示されます。

1 undefined

そしてその後、window.x存在しません。私たちの宣言のおかげで、どこにも言及されていません。宣言の代入部分が必要かどうかはわかりません。そうであってはなりません。しかし、割り当ても存在しない場合、IE の一部のバージョンが宣言を無視することを知っても驚かないでしょう。

これと比較してください:

var f = function() {
  x = 1;
  console.log(x, window.x);
  return;
  x = 2;  // this line truly does nothing.
};
f();

コンソールに次のように表示されます。

1 1

そしてその後、windows.xです1

definedAfter()変数代入形式で書かれていないため、正しく動作することも注目に値します。

// this puts definedAfter in scope, but it's undefined unless this line is
// actually executed
var definedAfter = function() { /* whatever */ }

代わりに、「実行」されない「関数宣言」形式で記述されています。

function definedAfter() { /* whatever */ }

むしろ、コンパイラはコンパイル中にそれを見て、「ああ、この関数はスコープの一部です」と言います。この違いにより、関数をいつ使用できるかを変数代入構文で正確に制御できるようになります。関数宣言形式では、実行順序を気にせずにどこでも関数を定義できます。

于 2013-04-15T16:35:03.117 に答える
0

いいえ、ライブラリのバグではありません。ただし、これは最も洗練されたコードではありません。

それをよりよく理解するために知っておくべき2つのことがあります

1) 巻き上げの意味 2) Function 式と Function 宣言の違いは微妙であり、ブラウザによって動作が異なります。

(後者については、http: //kangax.github.io/nfeを参照)

乾杯

于 2013-04-15T16:38:42.663 に答える