JavaScriptでのwithの使い方

青灯夜游
青灯夜游オリジナル
2022-03-28 16:49:211727ブラウズ

JavaScript では、with はステートメントのスコープ チェーンを拡張するために使用されます。これは通常、オブジェクト自体を繰り返し参照せずに、同じオブジェクト内の複数のプロパティを繰り返し参照するためのショートカットとして使用されます。構文は "with (式) {ステートメントを実行...}"。

JavaScriptでのwithの使い方

このチュートリアルの動作環境: Windows7 システム、JavaScript バージョン 1.8.5、Dell G3 コンピューター。

JavaScript with の基本的な使用法

#with ステートメントの本来の目的は、level-by に名前空間スタイルの短縮メソッドを提供することです。 -レベル オブジェクト アクセス また、指定されたコード領域では、オブジェクトはノード名を通じて直接呼び出されます。

with ステートメントは、ステートメントのスコープ チェーンを拡張するために使用されます。構文は次のとおりです。

with (expression) {
    statement
}
  • expression

    ステートメントの評価時に使用されるスコープ チェーンに指定された式を追加します。式を囲むかっこは必須です。

  • ステートメント

    任意のステートメント。複数のステートメントを実行するには、ブロック ステートメント ({ ... }) を使用してステートメントをグループ化します。

with は通常、オブジェクト自体を繰り返し参照せずに、同じオブジェクト内の複数のプロパティを繰り返し参照するためのショートカットとして使用されます。

たとえば、現在次のようなオブジェクトがあります。

var obj = {
	a: 1,
	b: 2,
	c: 3
};

obj の各項目の値を変更したい場合、一般的な書き方は次のようになります。

// 重复写了3次的“obj”
obj.a = 2;
obj.b = 3;
obj.c = 4;

そして、with 記述メソッドを使用することで簡単なショートカットが作成されます

with (obj) {
	a = 3;
	b = 4;
	c = 5;
}

このコードでは、with ステートメントを使用して obj オブジェクトを関連付けます。つまり、with コード ブロック内で各変数が最初に配置されます。ローカル変数と見なされ、ローカル変数が obj オブジェクトのプロパティと同じ名前を持つ場合、このローカル変数は obj オブジェクトのプロパティを指します。

with の欠点


上記の例では、with がコードを非常に単純化するのに役立つことがわかります。しかし、なぜ推奨されないのでしょうか? with の欠点について話しましょう:

データ漏洩につながる

コードの次の部分を見てみましょう

function foo(obj) {
	with (obj) {
		a = 2;
	}
}

var o1 = {
	a: 3
};

var o2 = {
	b: 3
}

foo(o1);
console.log(o1.a);	//2

foo(o2);
console.log(o2.a);	//underfined
console.log(a);		//2,a被泄漏到全局作用域上

まず、分析しましょう上のコード。この例では、2 つのオブジェクト o1 と o2 が作成されます。そのうちの 1 つは a 属性を持っていますが、もう 1 つは持っていません。 foo(obj) この関数は、オブジェクト参照である obj の仮パラメータを受け取り、オブジェクト参照に対して with(obj) {...} を実行します。 with ブロック内には、実際には LHS 参照である a への字句参照があり、それに 2 が割り当てられます。

o1 を渡すと、a = 2 代入操作により o1.a が見つかり、それに 2 が代入されます。 o2 が渡されると、o2 にはプロパティがないため、このプロパティは作成されず、o2.a は未定義のままになります。

しかし、なぜ o2 の操作がデータ漏洩につながるのでしょうか?

ここで、LHS クエリ のメカニズムに戻る必要があります。

with に o2 を渡すと、with で宣言されたスコープは o2 となり、このスコープを起点として LHS クエリが実行されます。識別子 a は、o2 のスコープ、foo(…) のスコープ、およびグローバル スコープで見つからないため、非厳密モードでは、グローバル変数がグローバル スコープで自動的に作成されます)。 Strict モードでは、ReferenceError 例外がスローされます。

with が推奨されないもう 1 つの理由は次のとおりです。厳密モードでは、eval(…) の間接的または安全でない使用と同様に、with は完全に禁止されています。

パフォーマンスの低下

with は、書き込み時に定義された他の字句スコープを欺くために、実行時に新しいスコープを変更または作成します。上記のデータ漏洩の可能性はありますが、ちょっとした注意で回避できますので、良い関数を作ることができるのではないでしょうか?

答えは「ノー」です。具体的な理由について、コードの次の部分を見てみましょう。

次のコードをコピーして直接実行できます

<script>
function func() {
	console.time("func");
	var obj = {
		a: [1, 2, 3]
	};
	for(var i = 0; i < 100000; i++)
	{
		var v = obj.a[0];
	}
	console.timeEnd("func");
}
func();

function funcWith() {
	console.time("funcWith");
	var obj = {
		a: [1, 2, 3]
	};
	with(obj) {
		for(var i = 0; i < 100000; i++) {
			var v = a[0];
		}
	}
	console.timeEnd("funcWith");
}

funcWith();
</script>

次に、テスト効果:

JavaScriptでのwithの使い方

In論理コードでは、with を使用しない場合の実行時間はわずか 4.63 ミリ秒です。 with使用時の使用時間は81.87msと長いです。 ######どうしてこれなの?

その理由は、

JavaScript エンジンがコンパイル段階でいくつかのパフォーマンスの最適化を実行するためです。これらの最適化の一部は、コードをその語彙集に基づいて静的に分析し、すべての変数と関数が定義されている場所を事前に決定して、実行中に識別子をすぐに見つけられるようにすることに依存しています。

しかし、エンジンがコード内で with を見つけた場合、新しい字句スコープを作成するために with に渡されたオブジェクトを知る方法がないため、識別子の位置に関する判断は無効であると単純に想定できます。 . いったいどんな内容なのか。

最も悲観的な状況は、with が表示された場合、すべての最適化が無意味になる可能性があることです。したがって、エンジンが採用する最も単純なアプローチは、最適化をまったく行わないです。コードで with または eval() を多量に使用すると、間違いなく実行が非常に遅くなります。エンジンがこれらの悲観的なシナリオの副作用を最小限に抑えようとしてどれほど賢明であっても、 これらの最適化がなければコードの実行が遅くなるという事実を避けることはできません。

【関連する推奨事項:

JavaScript ビデオ チュートリアル Web フロントエンド ]

以上がJavaScriptでのwithの使い方の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。