4 个回答

因为变量提升的缘故,你的第一段代码实际上等效于

var i

for (i = 0; i < 3; i++) {
  i = 3
  console.log(i)
}

第一次循环后, i 被赋值成了 3 ,所以第二次的时候, i < 3 不成立了,就不会执行了。

如果你想要达到预期,就应该使用函数创建一个新的作用域,这样就可以了。

for (var i = 0; i < 3; i++) {
  (function () {
    var i = 3
    console.log(i)
  })()
}

let、const 才有块级作用域概念, var 是没有的


所有上古年间,只有 function 是真块级

这个问题其实是看基础扎不扎实了, 如果理解了varletconst 这三个关键字的区别,那么就能明白为什么这三个for循环的输出是这样,那么我们先来了解下基础概念:

JavaScript中var、let、const关键字的区别

先谈谈letconst吧,varjs蛮荒时代的遗留产品。

let 关键字的特性

let的使用和var是差不多,和var的区别是

  1. let只会在它所声明的块中生效。请看代码:

    {
      let a = 10;
      var b = 1;
    }
    a // 代码块外访问a 会报错 ReferenceError: a is not defined.
    b // 代码块外访问b,可以拿到数据 1
  2. let不存在变量提升。请看代码

    // var 的情况
    console.log(foo); // 输出undefined
    var foo = 2;
    
    // let 的情况
    console.log(bar); // 报错ReferenceError
    let bar = 2;
  3. 在相同作用域内不允许重复声明同一变量。请看代码

    // 报错
    {
     var a = 10;
     let a = 10;
    }
    // 报错
    {
     let a = 1;
     let a = 2;
    }
  4. 不能在let变量声前使用(TDZ暂时性死区)。请看代码

     {
      // TDZ开始
      tmp = 'abc'; // 报错: ReferenceError
      console.log(tmp); // 报错: ReferenceError
    
      let tmp; // TDZ结束
      console.log(tmp); // undefined
    
      tmp = 123;
      console.log(tmp); // 123
    }
  5. let声明的变量会绑定当前作用,不受外部变量影响

    var tmp = 123;
    
    if (true) {
      console.log(tmp) // 报错(触发暂时性死区):ReferenceError
      let tmp = 'abc';
      console.log(tmp) // abc
    }

const 关键字

const包含let的所有特性,但const 声明的变量是常量。不能重复赋值。let是可以的.

const aa = 111;
console.log(aa) // 111
aa = 222; // 报错 TypeError: Assignment to constant variable.
console.log(aa) // 111

var关键字

  1. var 存在变量提升
  2. 对于var来讲,在function中才有作用域。如果不在function中那么就是全局作用域
  3. var 可以重复声明同一变量
  4. var 可以给变量重复赋值
  5. var 可以在变量未声明之前去使用变量(变量提升导致的)

回归正题,解答问题

理解了上面var、let、const的相关特性后,再来看题主的问题:

第一个循环为什么只输出了一次3?

for (var i =0; i < 3; i++) {
    var i = 3;
    console.log(i)
}

解析

  • 因为变量i是通过var 声明的。所以i会存在变量提升,i将会提升到全局作用域中。
  • 在循环体内重新声明了 var i = 3。那么var 声明的变量作用域只有function全局。所以这一步操作会将全局变量i重新赋值为3.
  • 进入第二次循环的,判断条件 i < 3 吗?不小于。所以循环结束了。

第二个循环输出 0 1 2

for (var i =0; i < 3; i++) {
    console.log(i)
}

解析
这个循环和第一个没有区别,只是循环体内少了一步操作:var i = 3。所以会循环到条件终止。

第三个循环为什么输出了3次3?

for (var i =0; i < 3; i++) {
    let i = 3;
    console.log(i)
}

解析

  • 对于let来讲,代码块是存在作用域的,其会绑定到当前的作用域中。外部变量并不会影响到该作用域中let声明的变量
  • 对于var来讲,代码块是不存在作用域的,所以var声明的变量会到全局中。
  • 循环使用的是全局作用域中的变量i, 所以会循环3
  • 代码块中console.log(i)输出的是let声明的变量i,所以会一直打印3.

最后

打完收功。
推荐题主看下es6相关的内容...
阮一峰的es6书籍:https://es6.ruanyifeng.com/

新手上路,请多包涵

当i=0,,第一次进入for循环体内时,i被赋值为3,输出3
程序继续执行,不符合再次进入循环体的条件(i<3),循环结束。
所以只输出一次

推荐问题
宣传栏