14

コード:

function test4() {
    var x = 10;
    var y = 100;
    // inner referred x only
    function inner () {
        console.log(x);
        debugger;
    }
    // inner2 referred y to make sure y is in the scope of inner
    function inner2 () {
        console.log(y);
    }
    return inner;
}
var foo = test4();
foo();

y一度も使用したことがないものにinner限りinner2ますので参考にしてください。スコープで結果を確認しましたがxyそこにあります:

x と y の閉鎖

しかし、ウォッチ パネルとコンソールで変数を確認したところ、すべてを取得できませんでした。

ウォッチ パネルで y を取得できません

yスコープ内にあるのに、デバッガーを使用するときに定義されないのは奇妙です。それで、それはデバッガーが現在のコンテキストで使用されていない変数にアクセスできないことを意味しますか? (私のクロムのバージョンは 51.0.2704.103 m です)

これは、なぜ Chrome デバッガーは、閉じたローカル変数が未定義であると考えるのですか?に似ています。しかし、同じではありません。inner2私のコードでは、それがクロージャーにあることを確認してくださいy。実際、私の質問は、その質問に対するルイスの回答とは反対です。

4

1 に答える 1

5

あなたは、スコープ最適化の内部メカニズムを直接観察しています。スコープの最適化は、現在のスコープで使用されている変数を確認し、未使用の変数へのアクセスを最適化します。その理由は、javascript の JIT コンパイルから生成されたマシン コードでは、変数命名の概念全体が失われているためです。ただし、JavaScript への準拠を維持するために、JIT コンパイラーは、使用されるローカル変数の配列を各 JavaScript 関数に関連付けます。次のコードを確認してください。

(function(){
  "use strict";
  var myVariable = NaN; // |Ref1|
  var scopedOne = (function(){
    var myVariable = 101; // |Ref2|
    return x => x * myVariable;
  })();
  var scopedTwo = (function(){
    var myVariable = -7; // |Ref3|
    return x => x / myVariable;
  })();
  console.log("scopedOne(2):  ", scopedOne(2));
  console.log("scopedTwo(56): ", scopedTwo(56))
})();

上記のように、Javascript は範囲指定されたスタックベースの言語です。Javascript がスコープ付き言語でない場合、関数で使用される変数は、関数が実行された場所の変数の値に依存します。たとえば、スコープがない場合はat |Ref1|scopedOneの値を使用します。|Ref2|の代わりに (NaN) (101) とログに記録しますmyVariableNaNコンソールに。要点に戻ると、マシンコードでは、デバッガーが起動すると、変数のみが使用されているため、それらのメモリ位置のみがマシンコードに永続化されているため、デバッガーは使用されている変数のメモリ内の実際の場所を把握することしかできません。 . 残りの変数のメモリ位置は謎のままです。ご覧のとおり、これには、スコープ内の未使用の変数をその関数から「見えなくする」という二次的な副作用があります。ただし、解決策があります。

この問題を回避するには、単純にdebugger;ステートメントを eval でラップして、ブラウザにスコープ内のすべての変数の高価な変数ルックアップを強制します。基本的に、ブラウザーは元のソース コードに戻り、スコープ内の変数の元の名前を調べて、JIT で生成されたマシン コードによって変数の値が格納されている場所を特定する必要があります。開発者ツールを開き、以下のスニペットを実行します。次に、[コール スタック] パネルの前のレベルに移動し、変数の値の可視性が、y目に見える内部evalから目に見えない外部にどのように変化するかを観察しますeval

function test4() {
    var x = 10;
    var y = 100;
    // inner referred x only
    function inner () {
        console.log(x);
        eval("debugger;");
    }
    // inner2 referred y to make sure y is in the scope of inner
    function inner2 () {
        console.log(y);
    }
    return inner;
}
var foo = test4();
foo();

于 2018-05-10T20:36:24.107 に答える