JavaScriptでのwithの使い方

jacklove
リリース: 2018-06-15 17:03:10
オリジナル
3540 人が閲覧しました

js の with キーワードといえば、多くの友人の第一印象は、with キーワードの機能はスコープの変更であり、最も重要な点は with キーワードの使用は推奨されないということでしょう。 with キーワードは推奨されないと聞くと、多くの人は with キーワードを無視して、無視して使用すればよいと考えます。しかし、コードや面接の質問を見ると、with キーワードに関連した質問が出てくることがあります。これまで経験したことのない落とし穴がたくさんあるため、with キーワードについて話しておく必要があります。

with の基本的な使用法 with ステートメントの本来の目的は、レベルごとのオブジェクト アクセスに名前空間スタイルの短縮メソッドを提供することです。つまり、指定されたコード領域で、オブジェクトが を介して直接呼び出されます。ノード名。

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);  //2foo(o2);
console.log(o2.a);  //underfinedconsole.log(a);     //不好,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 は未定義のままになります。

foo(obj) 函数接受一个 obj 的形参,该参数是一个对象引用,并对该对象医用执行了 with(obj) {...}。在 with 块内部,对 a 有一个词法引用,实际上是一个 LHS引用,将 2 赋值给了它。
  当我们将 o1 传递进去,a = 2 赋值操作找到了 o1.a 并将 2 赋值给它。而当 o2 传递进去,o2 并没有 a 的属性,因此不会创建这个属性,o2.a 保持 undefined。


  但为什么对 o2的操作会导致数据的泄漏呢?
  这里需要回到对 LHS查询 的机制问题(详情可移步 JavaScript中的LHS和RHS查询)。
  当我们传递 o2 给 with 时,with 所声明的作用域是 o2, 从这个作用域开始对 a 进行 LHS查询。o2 的作用域、foo(…) 的作用域和全局作用域中都没有找到标识符 a,因此在非严格模式下,会自动在全局作用域创建一个全局变量),在严格模式下,会抛出ReferenceError しかし、なぜo2の運用が情報漏洩につながるのでしょうか?

ここで、LHS クエリ のメカニズムに戻る必要があります (詳細については、JavaScript の LHS クエリと RHS クエリを参照してください)。
o2 を with に渡すと、with で宣言されたスコープは o2 となり、a の LHS クエリ はこのスコープから開始されます。識別子 a は、o2 のスコープ、foo(...) のスコープ、およびグローバル スコープでは見つからないため、非厳密モードでは、グローバル変数がグローバル スコープに自動的に作成されます。スコープ)、厳密モードでは、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の使い方


🎜🎜

同じロジックを処理するコードの実行時間は、ありなしの場合はわずか 4.63 ミリ秒です。 with使用時の使用時間は81.87msと長いです。


これはなぜですか?
その理由は、JavaScript エンジンがコンパイル段階でいくつかのパフォーマンスの最適化を実行するためです。これらの最適化の一部は、コードをその語彙集に基づいて静的に分析し、すべての変数と関数が定義されている場所を事前に決定して、実行中に識別子をすぐに見つけられるようにすることに依存しています。
しかし、エンジンがコード内で with を見つけた場合、新しい字句スコープの作成に使用された with に渡されたオブジェクトの内容を知る方法がないため、識別子の位置に関する判断は無効であると単純に想定できます。は。
最も悲観的なケースは、with が出現した場合、すべての最適化が無意味になる可能性があるということです。したがって、エンジンが採用する最も単純なアプローチは、最適化をまったく行わないことです。コードで with または eval() を多量に使用すると、間違いなく実行が非常に遅くなります。エンジンがこれらの悲観的な状況による副作用を最小限に抑えようとしてどれほど賢明であっても、これらの最適化がなければコードの実行が遅くなるという事実を避けることはできません この記事では、JavaScript での with の使用法について説明します。その他の関連コンテンツについては、php 中国語 Web サイトを参照してください。

関連する推奨事項:

js と php のネスト


js はデフォルトのイベントを防ぎ、js はバブリングイベントをブロックする例を共有します


js 関数の一般的な書き込みメソッドと呼び出しメソッド

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

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート