最常见的面试题之for循环

2018-09-08  本文已影响124人  MrOldK

小伙伴们去面试,可能常常会问到以下这个题。

   for(var i=0;i<10;i++){
        setTimeout(function(){
            console.log(i)
        },100)
    }//输出:10个10

这道题考察的重点是var声明变量的作用域问题。如果对种问题不熟的同学,最后说出的答案可能就是1,2,3,4,5,6,7,8,9,10
看到过有博客上写这个跟 setTimeout也有关系, setTimeout是个异步任务,会被浏览器加入到任务队列,等待100ms后执行。for循环是同步任务,主线程会执行完同步任务以后,再去任务队列执行异步任务的回调函数。当然这种说法也没错, 但这不是核心问题。如果用let来声明呢??

//变形一
   for(var i=0;i<10;i++){
        setTimeout(function(){
            console.log(i)
        },100)
    }//输出:1,2,3,4,5,6,7,8,9,10

这就看出来,仅仅只改变变量的声明关键字,问题就会迎刃而解。所以setTimeout的存在与否并没有影响。
在for循环语句中,用var声明的变量会上升到全局,之所以会这样,就是因为ES5语法中没有,没有块级作用域,而ES6中新增了块级作用域。 块作用域由 { } 包括,if语句和for语句里面的{ }也属于块作用域。
所以let声明的变量会绑定到当前作用域,每一次循环,都是一个块级作用域的生成,所以只在本次循环内有效。
那如果还是用var关键字声明变量,怎样实现let的效果呢??

//变形二  
    for(var i=0;i<10;i++){
        (function(){
            var index = i;
            setTimeout(function(){
                console.log(index)
            })
        })()
    }//输出:1,2,3,4,5,6,7,8,9,10

通过用自执行函数的形式,将每一次循环的i,赋值给一个变量index,用index来保存,形成最终的闭包。也就是将i绑定到当前局部作用域,成为setTimeout回调函数的私有变量,不会被浏览器回收。也可以这样:

//变形三 
    for(var i=0;i<10;i++){
        (function(index){
            setTimeout(function(){
                console.log(index)
            })
        })(i)
    }//输出:1,2,3,4,5,6,7,8,9,10
//变形四 
 function timeout(index){
    setTimeout(function(){
        console.log(index)
    })
 }
for(var i=0;i<10;i++){
    timeout(i)
}//输出:1,2,3,4,5,6,7,8,9,10

其实变形二和变形三,变形四的道理是一样的,这里不过多叙述。
以上个人简介,如有错误请指正。

上一篇下一篇

猜你喜欢

热点阅读