通常、実行コンテキストのスコープチェーンは変更されません
JavaScriptの字句スコープは静的ではありません
(字句スコープ/静的スコープ: コードを書く際の関数宣言位置によってスコープが決まります)
いくつかありますレキシコンを欺くことができるメカニズム
それらは with()、eval()、および try-catch ステートメントの catch 節です
それらの間で with と eval を使用すべきではありません (多くの問題が発生します)
レキシコンを騙す意味は、字句スコープを欺くことです
言い換えると、実行時にスコープチェーンを変更します
ここで、字句スコープを欺くことができるこれらのメカニズムについて説明します
eval()関数はパラメータとして文字列を受け取ります、そして文字列を解析してコードを生成しました
var a = 123;eval('console.log(a)');// 123
そのため、コンソールは 123 を出力しました
eval 関数の実行後
JS エンジンは、このコードが動的に挿入されたことを認識せず、スコープ チェーンを変更しました
エンジンは通常どおり関数を検索しますドメインチェーン
以下のコードを見てください
var a = 1;function demo(){ eval('var a = 2;');//欺骗词法 console.log(a);// 2} demo();
eval関数が実行されると、デモ関数実行環境の最上位スコープに変数aが追加されます
このローカル環境のaがグローバル環境のaを「影付け」します
最終的には印刷するプログラム 2
eval() 関数は、現在のスコープを変更できるだけでなく、グローバル スコープも変更できます
何があっても、実行時に字句スコープを変更できます
ES5 の厳密モードではこの関数が追加されますいくつかの制限があるため、上記のコードをローカルの厳密モードに追加しました
var a = 1;function demo(){ 'use strict'; eval('var a = 2;'); console.log(a);// 1} demo();
今度はコンソールに 1 が出力されることがわかりました
これは、厳密モードでは、eval() が実行時に独自の独立した字句スコープを持っているためです (保存します) スコープの問題
このように、その中の宣言は、その宣言が含まれるスコープを変更することはできません。
それによく似たコードを動的に生成できる他の 2 種類のコードがあります
タイマー setTimeout() と setInterval () 最初のパラメーターはコード文字列
にすることができ、関数コンストラクター new Function() の最後のパラメーターもコード文字列
を受け入れます。この使用法は、深刻なパフォーマンスの問題を引き起こすため、使用しないでください。これについては後ほど説明します
辞書をチートするために使用することをお勧めしない別の構文は with キーワードです
with は通常、オブジェクトの複数のプロパティを繰り返し参照するためのショートカットとして使用されます
利点は、繰り返し参照する必要がないことです必要なのはオブジェクトそのもの
例えばコンソールオブジェクトを再利用したい
console.log(1);console.info(2);console.warn(3);
withキーワードを使う
with(console){ log(1); info(2); warn(3); }
withでも問題なさそうなのですが、以下を見てみると
function demo(obj){ with(obj){ a = 5; } }var obj1 = {a:1};var obj2 = {b:2}; demo(obj1); console.log(obj1.a);// 5demo(obj2); console.log(obj2.a);// undefinedconsole.log(a);//5 -->变量a居然泄漏到了全局环境
obj1 は with キーワードを使用して変更されています
しかし、それは obj2 に追加されないだけでなく、副作用が全世界に漏洩しました
これは、with がオブジェクトを完全に分離された字句スコープとして扱うことができるためです (それを先頭に置きます)スコープ チェーンの)
その内部で実行が生成されますa = 5;
スコープ チェーンを調べますが、見つからないため、(var 宣言なしで) 変数をグローバルに作成します
注: with は字句スコープを作成しますが、 with 内の通常の var 宣言は、このブロックのスコープに制限されます
つまり、with の外側で宣言されたスコープは次のようになります
function demo(){ var obj = {}; with(obj){ var b = 1; console.log(b); // 1 } console.log(b); // 1} demo(); console.log(b);// Uncaught ReferenceError: b is not defined
これを使用しようとすると、次のようなエラーが表示されます:
try コード ブロックでエラーが発生すると、実行フローはすぐに catch 句にジャンプします
次に、例外オブジェクトを可変オブジェクトにプッシュし、スコープ チェーンの先頭に置きます。これは
の場合と非常によく似ています。 catch句が実行されると、スコープチェーンは元の状態に戻ります
JS エンジンはコンパイル段階でパフォーマンスの最適化を実行し、多くの最適化はコードに従ってコードを調整できるかどうかに依存しています
変数の定義位置を事前に決定します。および関数は、識別子を素早く見つけるための関数です
ただし、 eval または with は、識別子の位置を決定できません (コードの実行中に存在し、静的に分析することはできません)
言い換えると:
eval では、with および with のすべての最適化が行われます。 JS エンジンは無意味です (単純にクールです) 無意味なので、JS エンジンは単に最適化されません
これにより、プログラムの実行が遅くなります
スコープを作成すると、それが配置されている関数のすべてのローカル変数が 2 番目のスコープ チェーン オブジェクト内に配置されます
アクセス コストが高くなります
try{ ...}catch(e){ handleError(e); }
この方法では、ローカル変数へのアクセスはありません
スコープ チェーンの一時的な変更はパフォーマンスに影響しません
字句スコープとは、コードを記述するときの関数宣言の位置によってスコープが決定されることを意味します
コンパイル時の字句解析フェーズでは、すべての識別子がどこでどのように宣言されているかを知ることができます
eval はコード文字列に対して計算を実行でき、借用することができますこれは実行時に字句スコープを変更します
字句スコープはオブジェクト参照をスコープとして扱うことによって実行時に作成されます
evalは厳密モードのドメインで独立した字句効果を生成します、スコープは変更できません
strict モードでの使用は禁止されています
eval と with (および catch) は、実行中にレキシコンを欺き、スコープ チェーンを変更することができます
eval と with Cause js エンジンは、コンパイル フェーズ中にスコープ検索を最適化できません(静的解析ができない)プログラムが遅くなる
ここまで言っておきますが、withキーワードとeval関数は使わないでください〜( ̄0 ̄)/
以上です。字句 eval、catch を欺く JavaScript の内容とそのパフォーマンスの問題 その他の関連コンテンツについては、PHP 中国語 Web サイト (www.php.cn) に注目してください。