js の with キーワードといえば、多くの友人の第一印象は、with キーワードの機能はスコープの変更であり、最も重要な点は with キーワードの使用は推奨されないということでしょう。 with キーワードは推奨されないと聞くと、多くの人は with キーワードを無視して、無視して使用すればよいと考えます。しかし、コードや面接の質問を見ると、with キーワードに関連した質問が出てくることがあります。これまで経験したことのない落とし穴がたくさんあるため、with キーワードについて話しておく必要があります。
1. 基本的な手順
JS 高度なプログラミングでは、with キーワードは次のように説明されます。 with ステートメントの機能は、コードのスコープを特定のスコープに設定することです。 基本的な構文は次のとおりです。
with (expression) statement;
with キーワードを使用する目的は、次の例のように、同じオブジェクトを複数回作成してアクセスする作業を簡素化することです。
var qs = location.search.substring(1); var hostName = location.hostname; var url = location.href;
with (location){ var qs = search.substring(1); var hostName = hostname; var url = href; }
の欠点 前の基本的な説明では、with の機能の 1 つはコードを単純化することであることがわかりました。しかし、なぜ推奨されないのでしょうか? with の欠点について話しましょう:
1. パフォーマンスの問題
まず、with キーワードを使用したパフォーマンスの問題について説明します。まず、2 つのコードを見てみましょう。
コードの最初の部分では with キーワードが使用されていません:
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");//0.847ms } func();
function funcWith() { console.time("funcWith"); var obj = { a: [1, 2, 3] }; var obj2 = { x: 2 }; with (obj2) { console.log(x); for (var i = 0; i < 100000; i++) { var v = obj.a[0]; } } console.timeEnd("funcWith");//84.808ms } funcWith();
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");//88.260ms } funcWith();
JS エンジンには、コードが実行される前にコンパイル フェーズがあります。 with キーワードが使用されていない場合、JS エンジンは a が obj の属性であることを認識し、コードを静的に分析して識別子の解析を強化し、したがって、コードの実行効率が向上します。 with キーワードを使用した後、JS エンジンは変数がローカル変数であるか obj の属性であるかを判断できません。そのため、JS エンジンは with キーワードに遭遇すると、このコードの最適化を放棄するため、実行効率が低下します。 。
with キーワードの使用によるパフォーマンスへのもう 1 つの影響は、js 圧縮ツールではこのコードを圧縮できないことです。これもパフォーマンスに影響を与える要因です。
前述したように、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 ); // undefined console.log( a ); // 2
ここまで述べてきましたが、 with キーワードの使用が推奨されない理由と、考えられる問題については皆さんも理解できたと思います。より複雑な状況を見てみましょう。次のコードを見てください:
在这段代码中,分别输出30,20,undefined的。涉及的知识点也比较多:with关键字,this关键字,变量提升等等,我们来一一解释一下。
1、this关键字
关于this关键字的文章google上面相当多,这里不再赘述,我们只需记住一点:this关键字始终指向调用函数的对象。在这里,foo函数中,this指向的就是obj对象。因此在with(this)语句块里面,可以直接通过x变量来访问obj的x属性。
2、变量提升
js中的变量提升也是一个经常遇到的问题,我们可以简单理解成在js中,变量声明会被提升到函数的顶部,尽管有的时候,它是在后面声明的。
所以上面的代码可以解析为:
var obj = { x: 10, foo: function () { var x;//声明局部变量x var y;//声明局部变量y with (obj) { x = 20;//访问变量x,在obj上找到x,则修改为20 y = 30;//访问变量y,在bojg上找不到y,则进一步查找,找到局部变量y,修改为30 console.log(y);//30//直接输出局部变量y, } } }; obj.foo(); console.log(obj.x);//20,obj.x已被修改为20 console.log(obj.y);//undefined,obj不存在y属性,则为undefined
上面的注释中,解释了代码的执行过程,相信大家已经理解了为什么会出处30,20,undefined的原因。
有兴趣的同学可以看看下面这段代码:
({ x: 10, foo: function () { function bar() { console.log(x); console.log(y); console.log(this.x); } with (this) { var x = 20; var y = 30; bar.call(this); } } }).foo();
这段代码会输出什么?为什么呢?
总结
本文总结了with语句的特点和弊端,总的来说,强烈不推荐使用with关键字。其实在日常编码中,我们只需要知道不去使用with就可以了,但是有的时候我们可能会遇到一些关于with的奇奇怪怪的问题,想要找出真正的原因,就要深入理解with关键字,这有助于我们去深入学习JS这门语言,同时也是学习JS的一个乐趣。