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实现淘宝京东6位数字支付密码效果

    JavaScript实现淘宝京东6位数字支付密码效果

    这篇文章主要为大家详细介绍了JavaScript实现淘宝京东6位数字支付密码效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-08-08
  • javascript深拷贝和浅拷贝详解

    javascript深拷贝和浅拷贝详解

    本文主要介绍了javascript深拷贝和浅拷贝的相关知识。具有很好的参考价值,下面跟着小编一起来看下吧
    2017-02-02
  • 浅谈JS函数定义方式的区别

    浅谈JS函数定义方式的区别

    下面小编就为大家带来一篇浅谈JS函数定义方式的区别。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-10-10
  • JS简单添加元素新节点的方法示例

    JS简单添加元素新节点的方法示例

    这篇文章主要介绍了JS简单添加元素新节点的方法,结合实例形式分析了javascript针对页面元素节点的创建、添加、克隆等相关操作技巧,需要的朋友可以参考下
    2018-02-02
  • 利用Promise自定义一个GET请求的函数示例代码

    利用Promise自定义一个GET请求的函数示例代码

    这篇文章主要给大家介绍了关于如何利用Promise自定义一个GET请求的函数的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Promise具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-03-03
  • 解决Layui数据表格的宽高问题

    解决Layui数据表格的宽高问题

    今天小编就为大家分享一篇解决Layui数据表格的宽高问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-09-09
  • 浅谈javascript中执行环境(作用域)与作用域链

    浅谈javascript中执行环境(作用域)与作用域链

    本文主要介绍了javascript中执行环境(作用域)与作用域链,并在文章结尾处做出了总结,感兴趣的朋友可以看下
    2016-12-12
  • 微信小程序实现打卡签到页面

    微信小程序实现打卡签到页面

    这篇文章主要为大家详细介绍了微信小程序实现打卡签到页面,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-09-09
  • js实现上传按钮并显示缩略图小轮子

    js实现上传按钮并显示缩略图小轮子

    这篇文章主要为大家详细介绍了js实现上传按钮并显示缩略图小轮子,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-05-05
  • javascript中attachEvent用法实例分析

    javascript中attachEvent用法实例分析

    这篇文章主要介绍了javascript中attachEvent用法,实例分析了javascript中事件绑定的相关技巧,需要的朋友可以参考下
    2015-05-05

最新评论