Learn about let again from a JS interview question

Yesterday, I happened to see a closure topic I recorded before:

for (var i = 0; i < 5; i++){
    setTimeout(console.log(i), i * 1000)
}

This code will output 0, 1, 2, 3, 4 in sequence, but the set time interval has no effect, because console.log() is a method call and is executed directly. Change it a bit:

for (var i = 0; i < 5; i++){
    setTimeout(function(){console.log(i)}, i * 1000)
}

After writing it as a function, the output result is 5 5s, and then change it and use the closure:

for (var i = 0; i < 5; i++){
    (function(i){setTimeout(function(){console.log(i)}, i * 1000)})(i)
}

Now you can print 0, 1, 2, 3, and 4 in sequence every 1 second. I believe everyone is familiar here, and some of them may have seen it many times.

The two main points of knowledge involved here are that the time set by setTimeout refers to how many seconds to join the execution queue; the i used by the closure is the value of the loop variable passed in each time, and when the closure is not used, it is directly used The loop variable, so at the end of the loop will output 5 5s.

It should have ended here. Since I have been practicing the features of ES2015, when I rewritten this code today, I replaced var with let, which resulted in correct output without using closures, so I checked the let's on MDN. material.

let is block-scoped, and I knew a bit about it before, but only vaguely. Now look at an example:

function test(){
  var x = 1;
  let y = 1;
  if (true){
    var x = 2; //同样的变量
    let y = 2; //不同的变量
    console.log('x:' + x + ' y:' + y) //2 2
  }
  console.log('x:' + x + ' y:' + y) //2 1
}

Therefore, in the following code,

for (let i = 0; i < 5; i++){
  setTimeout(function(){
    console.log(i)
  }, i * 1000)
}

The anonymous function uses five different instances of i, so it can print 0, 1, 2, 3, 4 in sequence every second.

Let's learn about the other differences between let and var:

// 在程序或者函数的顶层,let并不会像var一样在全局对象上创造一个属性
var x = 'global'; // 挂载在window对象上,成为它的一个属性
let y = 'global'; // 不挂载在window对象上
console.log(this.x); // "global"
console.log(this.y); // undefined
console.log(y); // "global" 
// 在相同的函数或块作用域内用let重新声明同一个变量会引发SyntaxError
if (true) {
  let foo;
  let foo; // Uncaught SyntaxError: Identifier 'foo' has already been declared
}

if (true) {
  var boo;
  var boo; // undefined
}
//let不具有声明提升作用,var具有,但仅仅是声明提升,并不会执行赋值,所以是undefined
function do_something() {
  console.log(bar); // undefined
  console.log(foo); // ReferenceError: foo is not defined
  var bar = 1;
  let foo = 2;
}
do_something();

Other examples related to let scope:

switch (x) {
  case 0:
    let foo;
    break;
    
  case 1:
    let foo; // TypeError for redeclaration.
    break;
}
// 以上代码会报错,可以将其中一个包含进块,如:
switch (x) {
  case 0:
    let foo;
    break;
    
  case 1: {
    let foo; // TypeError for redeclaration.
    break;
  }
}
var a = 1;
var b = 2;

if (a === 1) {
  var a = 11; // the scope is global
  let b = 22; // the scope is inside the if-block

  console.log(a);  // 11
  console.log(b);  // 22
} 

console.log(a); // 11
console.log(b); // 2
//
function test(){
   var foo = 33;
   if (true) {
      let foo = (foo + 55); // ReferenceError
   }
}
test();

Reference: MDN let

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325114519&siteId=291194637