首页 > 试题广场 >

以上代码执行的结果是?

[单选题]
for(var i=0;i<5;++i){
    setTimeout(function(){
        console.log(i+ ' ');
    },100);
}
以上代码执行的结果是?
  • 5 5 5 5 5
  • 0 0 0 0 0
  • 0 1 2 3 4
  • 1 2 3 4 5
推荐
链接:https://www.nowcoder.com/questionTerminal/071f74e92c5e4605b9c5f4af16054c14?toCommentId=415706
来源:牛客网

更加详细的解释:注意理解困难的根本原因就是在循环的过程中,匿名函数根本就没有立即执行,证明的方法很简单,就是在匿名函数的后面加上(),输出结果会很明朗01234。正因为没有立即执行,所以在循环的过程中,匿名函数没有及时访问到每一个变量,这样外部函数循环完成之后,匿名函数才执行开始访问外部函数的变量,而这时变量的值早已成为最后一个
编辑于 2017-03-19 19:33:28 回复(1)
每次循环进来之后,由于setTimeout(),内部的匿名函数并没有立即执行,而是等到100ms后,而此时i早已变为5。
1)可以利用匿名函数创建立即执行函数(或者叫模仿跨级作用域)来解决这个问题;
for(var i=0;i<5;++i){
(function(num){
setTimeout(function(){
console.log(num+ ' ');
},100);
})(i);
}
创建立即执行函数并传入参数i。 因为函数的参数是按值传递的,所以i的当前值就赋值给了num,并传递给了setTimeout 中的闭包,在闭包中保存了i当前值的一个副本。
看到这里是不是要给我点个赞呢!
2)也可以使用ES6中的 let命令
for(let i=0;i<5;++i){
    setTimeout(function(){
        console.log(i+'');
    },100);
}

编辑于 2017-08-22 10:59:56 回复(7)
setTimeout() 是异步的,只有等到主线上的都执行完,才会执行异步的,此时i已经变成5。由于共循环了5次,异步队列中存放了 五次setTimeout(),会按照队列的顺序依次执行,且共同访问的是同一个变量。所以每次结果都是5,特别强调一下,这里和setTimetou(function,100)中的100 无关,假如:setTimeout(function,0),变成0 结果也是一样的。
发表于 2018-07-05 11:02:51 回复(3)
setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式。 所以匿名函数根本就没有立即执行,而是在100毫秒后执行,匿名函数开始访问外部函数的变量时,变量的值早已成为最后一个即5
发表于 2017-03-11 23:26:50 回复(5)
for(var i=0;i<5;++i){
    (function(i){
		setTimeout(function(){alert(i+ ' ');},100);
	})(i)
}
0,1,2,3,4

for(var i=0;i<5;++i){

		setTimeout(function(){alert(i+ ' ');},100);
}
5,5,5,5,5
使用闭包可以得到0到4,但是这里需要注意保存这些数据会一直占用内存, 
在不用时应该及时销毁。
编辑于 2017-09-08 09:19:25 回复(0)
闭包只能取得包含函数中的变量的最后一个值。
换句话说,闭包中的i不会从0->5,i只是5。
闭包所保存的是整个变量对象,而不是某个特殊变量
发表于 2017-04-02 17:21:47 回复(3)
答案添加一个44444
发表于 2017-06-28 18:02:42 回复(1)
來自 https://segmentfault.com/q/1010000004335132/a-1020000004335177

发表于 2017-01-22 16:40:39 回复(0)
延时函数的回调会在循环结束时才执行,尽管循环中的五个函数是在各个迭代中分别定义的,但是他们都被封闭在一个共享的全局作用域中,实际上只有一个i,当循环结束时,i变成了5
发表于 2018-08-01 09:21:44 回复(0)
这道题出的并不好 其实100应该换成0
发表于 2021-12-28 19:06:47 回复(0)
首先:理解for循环是同步的,setTimeout是异步的
1)for循环是同步的,setTimeout是异步的,每执行一次for循环就会把一个setTimeout放到异步队列里。
2)所以for循环执行5次异步队列里就有5个setTimeout。
3)同步的执行完就会执行异步的,所以等到第5个for循环结束之后,才去执行异步队列的setTimeout。

其次:理解var let 以及for循环的全局作用域。结果为55555
1)for(var i=0;i<5;++i){}  相当于var i;  for( i=0;i<5;++i){}    也相当于let i;  for( i=0;i<5;++i){}  (注意let i也是在全局声明的)
2)此时的i是全局变量,setTimeout里访问的都是全局变量的i.
3)i是1时setTimeout里的i也是1,i是2时setTimeout里的i也是2。。。最后全局的i变成5了,才去执行异步队列的setTimeout,所以此时异步队列访问到的i就都是5.

最后:重点理解 let 用于for循环的块级作用域(局部作用域)。(结果为01234
1)for(let i=0;i<5;++i){}  let在for循环里是有块级作用域的。
此时的i是for循环块级作用域里的i, 传到{}里的i是什么,setTimeout里访问到i就是什么,因为此时setTimeout访问的i不再是全局变量的i,而是传进来的局部变量i。(注意:也是for循环执行完毕之后,才去执行5个异步队列的setTimeout的
2)如果用var 声明i,也可以用闭包来模仿块级作用域(局部作用域)。
for(var i=0;i<5;++i){
        (function(num){
                setTimeout(function(){
                    console.log(num+ ' ');
                },100);
         })(i);
}
创建立即执行函数并传入参数i。 因为函数的参数是按值传递的,所以i的当前值就赋值给了num,并传递给了setTimeout 中的闭包,在闭包中保存了i当前值的一个副本。
编辑于 2021-12-20 12:54:15 回复(2)
++i与i++,理解了就知道如何解答了。

发表于 2019-06-01 16:29:57 回复(0)
setTimeout 定义和用法: setTimeout()方法用于在指定的毫秒数后调用函数或计算表达式。   语法: setTimeout(code,millisec)   参数: code (必需):要调用的函数后要执行的 JavaScript 代码串。millisec(必需):在执行代码前需等待的毫秒数。  提示: setTimeout() 只执行 code 一次。如果要多次调用,请使用 setInterval() 或者让 code 自身再次调用 setTimeout()。
发表于 2017-03-29 12:52:53 回复(0)
首先已知的是 setTimeout 这是一个异步函数。我的理解是 var 关键字会造成 作用域 提升,那么 i 会变成全局变量,当 for 这个同步代码执行完之后,i 变成 5,这时候再去执行异步函数,那么获取的就是 5。

如果将 var 改为 let,就是将 全局变量 改成 局部变量,自然 setTimeout 获取的就是局部变量的值,那么结果就是按顺序排列,结果为 0,1,2,3,4,5
编辑于 2023-12-12 14:46:54 回复(0)
Settimeout是异步.等到100 Ms后i早变为5
发表于 2023-10-31 14:50:11 回复(0)

a


编辑于 2023-02-07 19:36:55 回复(0)
这题用事件循环机制直接秒杀
发表于 2022-07-03 14:26:32 回复(0)
setTimout() 是异步的,只有等主线程执行完毕才会执行异步,当主线程执行完毕,这个时候i已经变成了5,由于循环了5次,所有这里变成了55555
发表于 2021-11-09 15:13:57 回复(0)
var声明的是(55555)let声明的是(12345)具体看牛客网
发表于 2021-09-26 22:46:45 回复(0)
简而言之:for循环拆开就是创建初始化i然后执行一次代码块,然后i自增一次,循环执行设计的次数。而i值在最后自增到5,在此之后调用i值都是5,set time out异步代码,会在第二次及以后事件循环中执行,那肯定都是输出5。思考一下代码执行顺序和作用域即可。ps,var在for等语句中不会产生块级作用域,就是全局变量,let则会在这种情况下创建块级作用域,从而保留放入时变量的值。
发表于 2021-08-29 17:03:27 回复(0)
如果要先执行里面的, 用let 或立即执行函数
发表于 2021-03-22 22:55:52 回复(0)