あなたは、スコープ最適化の内部メカニズムを直接観察しています。スコープの最適化は、現在のスコープで使用されている変数を確認し、未使用の変数へのアクセスを最適化します。その理由は、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) とログに記録しますmyVariable
NaN
コンソールに。要点に戻ると、マシンコードでは、デバッガーが起動すると、変数のみが使用されているため、それらのメモリ位置のみがマシンコードに永続化されているため、デバッガーは使用されている変数のメモリ内の実際の場所を把握することしかできません。 . 残りの変数のメモリ位置は謎のままです。ご覧のとおり、これには、スコープ内の未使用の変数をその関数から「見えなくする」という二次的な副作用があります。ただし、解決策があります。
この問題を回避するには、単純に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();