Speaking of the with keyword in js, the first impression of many friends may be that the function of the with keyword is to change the scope, and the most important point is that the use of the with keyword is not recommended. After hearing that the with keyword is not recommended, many of us will ignore the with keyword, thinking that we can just ignore it and just use it. But sometimes, when we look at some code or interview questions, there will be questions related to the with keyword. There are many pitfalls that you have never been exposed to, so it is still necessary to talk about the with keyword.
1. Basic instructions
The with keyword is described in js advanced programming like this: The function of the with statement is to set the scope of the code to a specific scope. The basic syntax is as follows:
with (expression) statement;
The purpose of using the with keyword is to simplify the work of writing and accessing the same object multiple times, such as the following example:
var qs = location.search.substring(1); var hostName = location.hostname; var url = location.href;
These lines of code access the properties in the location object. If you use the with keyword, the code can be simplified as follows:
with (location){ var qs = search.substring(1); var hostName = hostname; var url = href; }
In this code, the with statement is used to associate the location object. This means that within the with code block, each variable is first considered a local variable. If the local variable has the same name as a property of the location object, , then this local variable will point to the location object attribute.
Note: The with statement cannot be used in strict mode.
2. Disadvantages of the with keyword
In the previous basic description, we can see that one of the functions of with is to simplify the code. But why is it not recommended? Let’s talk about the shortcomings of with:
1. Performance issues
2. Unclear semantics and difficult to debug
3. Performance issues
First let’s talk about performance issues. Regarding the performance issues using the with keyword, first let’s take a look at two pieces of code:
The first piece of code does not use the with keyword:
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();
The second piece of code uses the with keyword:
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();
After using the with keyword, the performance of the code is greatly reduced. The with statement in the second piece of code acts on the obj2 object, and then the obj object is accessed in the with block. There is a view that after using the with keyword, when accessing a variable in the with block, it will first search whether there is an attribute named obj on obj2. If not, then proceed to the next search. This process leads to a decrease in performance. But is this really the reason why program performance actually degrades?
Let’s modify the second piece of code as follows:
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();
This code applies the with statement to the obj object, and then directly uses a to access the a attribute of obj. According to the previously mentioned point of view, when accessing the a attribute, the attribute can be found on obj in one go. But why is the code performance still reduced?
The real reason is: after using the with keyword, the JS engine cannot optimize this code.
The JS engine has a compilation phase before the code is executed. When the with keyword is not used, the JS engine knows that a is an attribute on obj, and it can statically analyze the code to enhance the parsing of the identifier, thus optimizing the code. Therefore The efficiency of code execution is improved. After using the with keyword, the js engine cannot tell whether the a variable is a local variable or an attribute of obj. Therefore, after the js engine encounters the with keyword, it will give up optimizing this code, so the execution efficiency is reduced. .
Another impact of using the with keyword on performance is the js compression tool, which cannot compress this code, which is also a factor affecting performance.
4. Unclear semantics and difficult to debug
As mentioned earlier, in addition to performance issues, with also has the disadvantage of unclear semantics and difficulty in debugging, which makes the code difficult to read and may cause potential bugs.
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
This code is easy to understand. In the foo function, the with keyword is used to access the passed in obj object, and then modify the a attribute. When the o1 object is passed in, because the o1 object has an attribute a, there is no problem. When the o2 object is passed in, when the a attribute is modified, since the o2 object does not have the a attribute, the modified a attribute becomes a global variable. This creates potential bugs.
5. Extended Analysis
Having said so much before, I believe everyone has understood why it is not recommended to use the with keyword and the possible problems. Let's take a look at some more complex situations, look at the following code:
var obj = { x: 10, foo: function () { with (this) { var x = 20; var y = 30; console.log(y);//30 } } }; obj.foo(); console.log(obj.x);//20 console.log(obj.y);//undefined
在这段代码中,分别输出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的一个乐趣。