首页 > 试题广场 >

以下代码执行的结果 for(var i=0;i3;++i.

[单选题]
以下代码执行的结果
for(var i=0;i<3;++i){
    setTimeout(function(){
        console.log(i);
    },100);
}

  • 0,1,2
  • 1,2,3
  • 3,3,3
  • 0,0,0
谢同学提醒,let 只能输出0,1,2。至于为什么--因为由let的特质决定无论i如何自增,都无法在本次循环里覆盖循环条件中的i。同时还要注意setTimeout这个异步操作,输出顺序可能为0,1,2的排列组合结果。(setTimeout是异步的,let每一次都生成一个新指针不会覆盖,无法判断指针指向保存数据的输出顺序)。这题换成let会复杂很多
编辑于 2019-09-17 13:50:37 回复(6)
每次for循环的时候setTimeout都会执行,因为setTimeout是异步函数,里面的function则不会立即执行,而是会被放入任务队列,因此放了3次;for循环的3次执行完之后,,i变为3,也就是每次循环,i都会被后一个i值覆盖,然后全部执行任务队列中的函数,所以就是输出3个3。
编辑于 2019-09-22 11:04:31 回复(2)
这道题涉及了异步、作用域、闭包
settimeout是异步执行,100ms后往任务队列里面添加一个任务,只有主线上的全部执行完,才会执行任务队列里的任务,当主线执行完成后,i是3,所以此时再去执行任务队列里的任务时,i全部是3了。对于打印3次是:
 每一次for循环的时候,settimeout都执行一次,但是里面的函数没有被执行,而是被放到了任务队列里面,等待执行,for循环了3次,就放了3次,当主线程执行完成后,才进入任务队列里面执行。
发表于 2020-03-22 15:03:04 回复(0)
需要注意var如果换成let就不一样了
发表于 2019-08-12 20:41:52 回复(5)
首先涉及知识点事件循环机制,浏览器是单线程程序,代码的执行顺序是先执行主线程里的同步任务,也就形成一个执行栈,第一次代码运行时:var i= 0;立即执行浏览器自带的API,即setTimeout,但是setTimeout里的函数function却不执行,哪怕这里的100毫秒改成0也一样,这个function函数的需要挂机进入异步任务,但此时的i=0;运行到这里,第一次代码运行结束。 
第二次代码运行:var i= 1;并再执行setTimeout,function函数再次挂起,放入异步任务队列中;
第三次代码运行:var i= 2;并再执行setTimeout,function函数再次挂起,放入异步任务队列中;
这三次代码运行是一个宏任务,宏任务执行完,就会去清空微任务,而此时的i在最后一次i=2执行完,++i后,i的值为3,++i是先加后赋值,而清空微任务即执行三次挂机的function函数,此时的i=3;故输出3,3,3;
而let 是ES6标准的具有块级作用域的声明,let=0时,形成的作用域是独立的,后面的function里的i不会被主线程里的宏任务的i=3所覆盖。
因为var声明编译和执行是分开的,let却只有在进入执行环境时才会被执行。
发表于 2021-06-18 02:14:19 回复(2)
ES6标准中用 let 解决了这个问题,当然用闭包包起来也可以
发表于 2019-09-15 15:56:58 回复(0)
每次for循环的时候setTimeout都会执行,因为setTimeout是异步函数,里面的function则不会立即执行,而是会被放入任务队列,因此放了3次;for循环的3次执行完之后,,i变为3,也就是每次循环,i都会被后一个i值覆盖,然后全部执行任务队列中的函数,所以就是输出3个3。
编辑于 2020-08-20 18:05:54 回复(0)
settimeout是异步执行,100ms后往任务队列里面添加一个任务,只有主线上的全部执行完,才会执行任务队列里的任务,当主线执行完成后,i是3,所以此时再去执行任务队列里的任务时,i全部是3了。对于打印3次是:
 每一次for循环的时候,settimeout都执行一次,但是里面的函数没有被执行,而是被放到了任务队列里面,等待执行,for循环了3次,就放了3次,当主线程执行完成后,才进入任务队列里面执行。
发表于 2022-07-17 14:01:56 回复(0)
let会在每个循环🔁单独创建一个变量引用,每个循环块的i是不同的;var 则是循环块共用这个变量; 关于闭包问题,因为settimeout的原因,function引用i的操作被延后了,所以没有形成存储当时状态下的i。
发表于 2024-04-19 09:57:15 回复(0)
JavaScript中,var声明的变量只有函数作用域,而没有块级作用域。这意味着:1. var声明的变量在函数内部anywhere都可以访问,不仅限于它被声明的块或语句中。2. 重复var声明,后面的会覆盖前面的。3. 离开函数后,var声明的变量就不再存在。这些特点导致上例中setTimeout回调函数引用的实际上是循环结束后全局作用域中的i,而非循环块内部的i。相比而言,ES6中引入的let具有块级作用域:1. let在同一个块中不允许重复声明。
2. let声明的变量只在声明它的块中可用。
3. 不会进行变量提升,必须先声明后使用。所以如果改用let,setTimeout回调函数引用的则是循环块内部的i值,可以解决这个问题。举个例子:
js
{
  var x = 1;
  let y = 1; 
}

console.log(x); //1
console.log(y); //y is not defined!
 这里,var x在全局作用域中可访问,而let y仅在块级作用域{}内可访问,outside无法访问。另一个例子:
js
console.log(foo); // undefined
var foo = 1;

console.log(bar); // ReferenceError!
let bar = 2;
这里,由于var有变量提升,foo先被声明,然后再赋值,所以第1行不会报错。
而let没有变量提升,必须先声明后使用,所以第3行会报错。所以总结来说,var的函数作用域特点主要体现在:1. 变量可在函数内部任意位置访问
2. 存在变量提升现象
3. 离开函数就释放而let则有块级作用域,没有上述特点,更严格地限制了变量的范围。
发表于 2023-04-17 15:45:52 回复(0)
100毫秒后匿名函数才开始执行,for循环里的程序已经完成,此时i=3,连续打印3遍,自然就是c选项
发表于 2022-10-09 09:41:56 回复(0)
每次for循环的时候setTimeout都会执行,因为setTimeout是异步函数,里面的function则不会立即执行,而是会被放入任务队列,因此放了3次;for循环的3次执行完之后,,i变为3,也就是每次循环,i都会被后一个i值覆盖,然后全部执行任务队列中的函数,所以就是输出3个3。
发表于 2022-04-24 20:30:35 回复(0)
let块级作用域,var函数作用域,然后setTimeout加到异步中
发表于 2021-12-30 11:04:38 回复(0)
参考楼下
setTimeOut是异步函数, 每次for循环都会执行setTimeOut, 但是function会放入一个micro队列.
100ms之后往任务队列里添加一个任务, 只有当主线上的线程都执行完后, 才会执行任务队列里的任务
发表于 2021-12-18 20:34:33 回复(0)
每次for循环执行的时候setTimeout都会执行,setTimeout是异步函数,里面的函数不会立即执行,而是等for循环执行完后才执行,所以输出3个3
发表于 2021-11-17 17:54:59 回复(0)
var创建的是全局变量 let创建局部变量
发表于 2021-10-02 09:29:56 回复(0)
setTimeOut放入宏任务队列 在栈里事件运行完 且微任务队列也运行完才运行。运行的时候循环已结束 全局变量i=3。
发表于 2021-07-30 22:48:54 回复(0)
这里是 var ,如果是let 就不是这样的了
发表于 2021-07-12 11:21:01 回复(0)
var 变 let 要试试看
发表于 2021-04-05 17:06:29 回复(0)
setTimeout执行是会放入等待队列 也就是先执行循环 结束循环后输出
发表于 2021-03-16 10:43:31 回复(0)