JavaScript新手必看之var在for循环中的坑

 更新时间:2023年05月25日 09:31:04   作者:JetTsang  
var这个关键字在JS当中是相当常用的,但同时配合到for循环的话会出现不符合预期的运行结果,所以本文就来为大家讲讲如何避免这种情况的出现

一道面试题

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

那么以上会输出什么呢?答案是控制台是依次输出0,1,2,3,4。相信大家小伙伴们都答对了。再接再厉吧,再来一道。

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

这次还会是同样的结论吗?答案是输出5次5。这里开始有疑惑了对吧,预期输出应该也是0,1,2,4才对,怎么会输出的是5呢?先开个结论,这里是和作用域有关系的。

引申

为了更进一步的去理解这个问题,来一个需求吧。用一个数组去存放函数,依次输出0-4之间的数吧。

var a = []
for (var i= 0;i<2;i++){
            a[i] =function(){
                    console.log(i)
            }
   }
a.forEach(_=>{
            _()
        })

答案同样是只能输出5。

原因就很简单,因为你的每一个函数都绑定的变量i,所以每次去执行函数,都会去访问这个变量i,因为var声明的变量,并不只局限在for循环当中,而是在全局当中生效了!而你又不是在循环当中去调用它的,而是在循环之后去调用。在循环时,i会伴随着循环增长,此时你调用的话,前面的确实a[i]的结果是i,但a[i-1],a[i-2]...的结果也是i,因为函数调用时,内部的i指向的是全局范围内的i。

换言之,你数组里的函数都是引用的这个全局变量i。而不是for循环里的局部变量i。

要想解决这个问题,请接着往下看。

解决思路

思路:既然var声明的是全局的变量,那么只要函数里的变量是局部的即可。

写法1

巧的是ES6当中的let声明关键字就是这个效果。

var a = []
for (let i= 0;i<2;i++){   //这里把原来的var声明改成了let声明
            a[i] =function(){
                    console.log(i)
            }
   }
a.forEach(_=>{
            _()
        })

那么可能会疑问,既然这个let声明的i是局部变量,那么每次循环都会重新创建1个i吧?

是的没错。

那么每次都重新创建的话,会不会i的值也会被重新初始化呢?

答案是不会,JS引擎在for循环当中会记住前一次结束时的i值,并且在下一次创建时将i赋值。

写法2

var a = []
for (var i= 0;i<2;i++){   
            a[i] = (function(i){
                        return function(){
                            console.log(i)
            })(i)
   }
a.forEach(_=>{
            _()
        })

这里的写法就是在每次循环当中,将循环中的i(i在不断增长),通过形参传进去,从而诞生出局部变量i。

附:形参传递的过程,基本数据类型就是将值赋给形参,而引用数据类型则是将指针赋给形参。

当心

可能会有这样想法的同学。这样做只是定义了函数,这个函数有1个形参i而已。这样你调用它就变成了a[i](xxx)。

var a = []
for (var i= 0;i<2;i++){   
            a[i] = function(i){
                            console.log(i)
            }
   }
a.forEach(_=>{
            _()
        })

想要传递参数只能是(fun(i){})(i),写成立即执行函数调用它,这样才能去给它传值(形参)。

var a = []
for (var i= 0;i<2;i++){   
            a[i] = (function(i){
                            console.log(i)
            })(i)
   }
a.forEach(_=>{
            _()
        })

而加入括号的时候,就会被执行了,因此我们需要套一层return。这样才能达到我们想要的效果

想要传递参数只能是(fun(i){})(i),写成立即执行函数调用它,这样才能去给它传值(形参)。

而加入括号的时候,就会被执行了,因此我们需要套一层return。这样才能达到我们想要的效果

到此这篇关于JavaScript新手必看之var在for循环中的坑的文章就介绍到这了,更多相关var for循环内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • JavaScript控制浏览器全屏显示简单示例

    JavaScript控制浏览器全屏显示简单示例

    这篇文章主要介绍了JavaScript控制浏览器全屏显示,结合简单实例形式分析了JavaScript响应鼠标事件控制浏览器全屏显示与退出全屏显示相关操作技巧,需要的朋友可以参考下
    2018-07-07
  • js页面跳转常用的几种方式

    js页面跳转常用的几种方式

    js实现页面跳转的几种方式,需要的朋友可以参考下。
    2010-11-11
  • JavaScript实现连连看连线算法

    JavaScript实现连连看连线算法

    这篇文章主要为大家详细介绍了JavaScript实现连连看连线算法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-01-01
  • 实用的js 焦点图切换效果 结构行为相分离

    实用的js 焦点图切换效果 结构行为相分离

    行为层是由js来实现的,这里的工作只是搭建了一个简单的骨架,如果要让效果图美观些并符合设计要求,就要发挥css的强大作用了。
    2010-06-06
  • Mozilla 表达式 __noSuchMethod__

    Mozilla 表达式 __noSuchMethod__

    这是一个很特殊的方法,但是其存在的意义很大。不过很可惜只有firefox支持了。一个简单的例子解释一下它的用处
    2009-04-04
  • 前端存储后端响应数据超详细的实现方式和注意事项

    前端存储后端响应数据超详细的实现方式和注意事项

    前端通过多种方式向后端获取数据,下面这篇文章主要介绍了前端存储后端响应数据超详细的实现方式和注意事项,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-03-03
  • JavaScript获取页面中表单(form)数量的方法

    JavaScript获取页面中表单(form)数量的方法

    这篇文章主要介绍了JavaScript获取页面中表单(form)数量的方法,涉及javascript操作表单document.forms数组的技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-04-04
  • 微信小程序实现留言功能

    微信小程序实现留言功能

    这篇文章主要为大家详细介绍了微信小程序实现留言功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-10-10
  • js变形金刚文字特效代码分享

    js变形金刚文字特效代码分享

    这篇文章主要介绍了js变形金刚文字特效,实现效果超酷,很立体,感兴趣的小伙伴们可以参考一下
    2015-08-08
  • JavaScript初学者需要了解10个小技巧

    JavaScript初学者需要了解10个小技巧

    在之前的编程语言排行榜中,我们曾介绍过转正在即的JavaScript语言,正如文章中阐明的那样,JavaScript不仅是最具活力的脚本语言,还是是最有用的编程语言之一。
    2010-08-08

最新评论