由一道JS面试题再次了解let

昨天偶然看到自己以前记录的一个闭包题目:

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

这段代码会依次输出0,1,2,3,4,但是设置的时间间隔却没有起到效果,因为console.log()是方法的调用,直接执行了。改动一下:

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

写成函数后,输出结果是5个5,再改动一下,使用闭包:

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

现在可以每隔1秒依次打印0,1,2,3,4了,到这里相信大家都不陌生,可能有的已经见过很多次了。

这里面涉及的两个主要知识点是,setTimeout设置的时间是指多少秒后加入执行队列;闭包使用的i是每次传入的循环变量的值,不使用闭包时,则是直接使用的循环变量,所以在循环结束时会输出5个5。

到这里本该结束了,由于一直在实践ES2015的特性,今天重新书写这段代码时,自己是把var替换成了let,就导致不使用闭包就可以正确输出,因此查阅了MDN上let的资料。

let是具有块级作用域的,以前也知道一点,但只是模糊的知道。现在看个例子:

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
}

因此,下面这段代码中,

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

匿名函数使用的是i的五个不同实例,所以可以每隔一秒依次打印0,1,2,3,4.

再来了解下let和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();

和let作用域相关的其他例子:

扫描二维码关注公众号,回复: 92593 查看本文章
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();

资料参考:MDN let

猜你喜欢

转载自my.oschina.net/u/1375322/blog/1800258