Understand the with keyword in javascript

  • 2020-12-18 01:45:59
  • OfStack

Speaking of the with keyword in js, many people's first impression may be that the purpose of the with keyword is to change the scope, and the most important point is that the with keyword is not recommended. When we hear that the with keyword is not recommended, many of us ignore the with keyword, thinking that we can just leave it alone and use it. But sometimes, when we look at some code or interview questions, there will be questions about the with keyword, many of which are new to you, so it's worth mentioning the with keyword.

1. Basic instructions

In js advanced programming, the with keyword is described as follows: the purpose 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 task of writing multiple accesses to the same 1 object, such as the following example:


var qs = location.search.substring(1);
var hostName = location.hostname;
var url = location.href;

These lines of code all access properties in the location object. Using the with keyword can simplify the code 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, which means that within the with block, each variable is first considered to be a local variable, which points to the location object property if it has the same name as an attribute of the location object.
Note: The with statement cannot be used in strict mode.

2. Disadvantages of the with keyword

In the basic explanation above, we can see that one of the purposes of with is to simplify the code. But why not recommend it? Here are the disadvantages of with:

1. Performance issues
2. Unclear semantics and difficult debugging

3. Performance issues

Let's start with the performance issue. With the with keyword, let's look at two pieces of code:

The first code is not using 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 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 was significantly reduced. The with statement in section 2 is applied to the obj2 object, and then the obj object is accessed inside the with block. One idea is that when the with keyword is used to access a variable within the with block, the property is first looked up on obj2 to see if it is named obj, and if it is not, the next step is looked up, which results in a performance degradation. But is this really the reason for the performance degradation?
We modify the first and second section of the 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 property of obj. According to the previous point of view, when accessing the a property, the property can be found on obj once, but why does the code performance still decrease?
The real reason: the JS engine cannot optimize this code with the with keyword.
The JS engine has a compilation phase before the code execution. When the with keyword is not used, the js engine knows that a is a property on obj. It can statically analyze the code to enhance the resolution of the identifier, thus optimizing the code, so the efficiency of code execution is improved. When the with keyword is used, the js engine cannot tell whether the a variable is a local variable or a property of obj, so when the js engine encounters the with keyword, it abandons the optimization of this code, so the execution efficiency is reduced.
Another performance impact of using the with keyword is the js compression tool, which is unable to compress this code, which is another factor in performance.

4. Unclear semantics, difficult to debug

In addition to the performance issues mentioned earlier, with also has one drawback, which is unclear semantics and difficult to debug. This makes the code difficult to read and potentially bug.


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 incoming obj object, and then the a attribute is modified. When an o1 object is passed in, there is no problem because the o1 object has the a attribute. When the o2 object is passed in, when the a attribute is modified, the modified a attribute becomes a global variable because the o2 object does not have the a attribute. This leads to a potential bug.

5. Extended analysis

Having said all that, I'm sure you understand why the with keyword is not recommended and why it might be problematic. Let's take a look at some of the more complicated cases, as shown in 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

In this code, output 30,20, undefined, respectively. There are also many knowledge points involved: with keyword, this keyword, variable promotion, etc., let's explain 1 in 11.
1. this keyword
The this keyword is quite extensive, so I won't repeat it here, but just remember one thing: the this keyword always points to the object calling the function. Here, in the foo function, this refers to the obj object. Therefore, in the with(this) statement block, the x attribute of obj can be accessed directly through the x variable.
2. Variable promotion
Variable promotion in js is also a common problem, which can be understood simply as in js, variable declarations are promoted to the top of functions, although sometimes they are declared later.

Therefore, the above code can be resolved as follows:


var obj = {
  x: 10,
  foo: function () {
    var x;// Declare local variables x
    var y;// Declare local variables y
    with (obj) {
      x = 20;// Access to the variable x In the obj Found on the x , then modify to 20
      y = 30;// Access to the variable y In the bojg Can't find on y , then into 1 Step lookup, find the local variable y , modified to 30
      console.log(y);//30// Direct output of local variables y . 
    }
  }
};
obj.foo();
console.log(obj.x);//20 . obj.x Has been modified to 20
console.log(obj.y);//undefined . obj There is no y Property, is undefined

In the comments above, the execution of the code is explained, and I'm sure you understand why the source is 30,20, undefined.

If you're interested, take a look at this code:


({
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();

What does this code output? Why is that?

conclusion

This paper summarizes the characteristics and disadvantages of with statement. In general, the use of with keyword is strongly not recommended. Actually in everyday coding, we just need to know not to use with is ok, but sometimes we may run into some strange about with 1 problem, want to find out the real cause, must understand with keyword, this will help us to further study JS this language, is also the one of learning JS fun.


Related articles: