经典的案例

let arr = []
for(var i =0;i<=5;i++){
arr[i]= function fn(){
console.log(i)
}
}
arr[0]() //6

解析:我们的想法是arr[0]的函数应该是打印0的,而且每个元素的函数都能打印出自己的索引才对,可结果出乎意料。实际上为啥是6,我们先逐步分析。

1.js没有块级作用域

for(var i =0;i<=5;i++){
b=3
console.log(i)
}
{var a =1}
console.log('结果:',a,b) //结果: 1 3

也就是说,在大括号中声明的变量在大括号外部能拿到。这些变量是全局变量。

2.函数操作的变量值是函数调用时的而非函数声明时的

var a = 1
var fn = function(){
console.log('a:',a)
}
a=2
fn() //a:2

函数声明时变量a的值是1,声明后a的值变成了2,此时再调用fn函数,取得的a是2.

3.for循环的变量泄漏

let arr = []
for(var i =0;i<=5;i++){
arr[i]= function fn(){
console.log('i',i)
}
}
//实际上此时的arr是,[fn,fn,fn,fn,fn,fn]
console.log('i:',i) //i:6
arr[0]() //i 6
//实际上就是 console.log('i',i),而此时的i变成了6,无论是数组的第几个元素,最终打印的都是6

如果我希望每个元素都是打印它的索引,如何解决这个问题

方案1:闭包

返回一个函数,实际上就是我希望函数里打印的变量时当时循环的i的值,那我就把这个值作为参数传进去.所以,我用函数去返回一个函数

let arr = []
for(var i =0;i<=5;i++){
var fn = function(a){
return function(){
console.log('i',a) //打印的并不是全局变量i,而是实参'i'
}
}
arr[i]= fn(i) //调用的时候,i是当前循环的值
}
arr[0]() //i 0

我们常说闭包可以用来延长变量的使用寿命,实际上就是单独用一个函数作用域去保存外部变量值.

方案2:let和const

let和const声明的变量常被视为块级作用域,即虽然js无块级作用域的说法,但是let 和const的功能可以被视作块级作用域

let arr = []
for(let i =0;i<=5;i++){
arr[i]= function fn(){
console.log('i:',i)
}
}
arr[0]() //i 0

如下:

let arr = []
{let a = 1
arr[0] =function (){
console.log('a:',a)
}}
{let a =2
arr[1] = function(){
console.log('a::',a)
}}
arr[0]() //a: 1
arr[1]() //a:: 2

说明,let声明的变量,在一个大括号里是可以视作独立的存在的。类似块级作用域的效果,如果把let换成var,那就会提升为全局变量,最后被后面的赋值修改。

for循环中的变量泄漏的更多相关文章

  1. js for 循环中的 变量问题。

    今日处理项目中的一个循环,本来就是一个小小的for循环,后来发现该段程序出现了问题,仔细检查代码没有发现其中的错误.无奈只好叫来了老大帮忙.通过在模版中断点调试(该方式只能自己写debugger断点) ...

  2. 【SQL】小心在循环中声明变量——浅析SQL变量作用域

    本文适用:T-SQL(SQL Server) 先看这个语句: --跑3圈 BEGIN --每圈都定义一个表变量,并插入一行 DECLARE @t TABLE(Col INT PRIMARY KEY) ...

  3. 用闭包解决 js 循环中函数变量暂存问题

    需求:有一个数组,根据数组的值渲染对应的数字div,单击对应的div 在控制台打印对应的数字.如点击1,控制台打印1. 问题: 不管点击哪个值 打出来都是4 代码如下 <!DOCTYPE htm ...

  4. Python语言程序设计之一--for循环中累加变量是否要清零

    最近学到了Pyhton中循环这一章.之前也断断续续学过,但都只是到了函数这一章就停下来了,写过的代码虽然保存了下来,但是当时的思路和总结都没有记录下来,很可惜.这次我开通了博客,就是要把这些珍贵的学习 ...

  5. 16.1 foreach 循环中捕获变量的变化

    在 foreach 循环内的匿名函数(通常为Lambda表达式)中捕获循环 变量时要格外小心.代码清单16-1就展示了这样一个简单的示例,它看上去似乎会输出 x . y . z . string[] ...

  6. 关于在for循环中绑定事件打印变量i是最后一次。

    其实函数引用的外部变量都是最后一次的值. <!DOCTYPE html> <html lang="en"> <head> <meta ch ...

  7. 关于while read line 循环中变量作用域的问题

    前一阵用shell写了一个从数据库中抽取数据生成.xml文件的脚本,要求是每个文件中只生成1000条数据.于是用到了while read line 作为循环. 在制作文件计数器的时候发现了一个问题,在 ...

  8. 注意for循环中变量的作用域-乾颐堂

    1 2 for e in collections:     pass 在for 循环里, 最后一个对象e一直存在在上下文中.就是在循环外面,接下来对e的引用仍然有效. 这里有个问题容易被忽略,如果在循 ...

  9. 注意for循环中变量的作用域

    for e in collections: pass 在for 循环里, 最后一个对象e一直存在在上下文中.就是在循环外面,接下来对e的引用仍然有效. 这里有个问题容易被忽略,如果在循环之前已经有一个 ...

随机推荐

  1. [luogu5361]热闹的聚会与尴尬的聚会

    由于两者是独立的,我们希望两者的$p$和$q$都最大 考虑最大的$p$,先全部邀请,此时要增大$p$显然必须要删去当前度数最小的点,不断删除之后将每一次度数最小值对答案取max即可 对于$q$也即最大 ...

  2. JavaWeb 请求转发重定向

    请求转发和重定向 request除了可以作为请求对象之外,还可以作为域对象,但是该域对象的取值范围,是一次请求范围之内(浏览器地址栏没有发生跳转访问别的资源) 作用:将servlet中的数据通过req ...

  3. 洛谷 P4002 - [清华集训2017]生成树计数(多项式)

    题面传送门 神题. 考虑将所有连通块缩成一个点,那么所有连好边的生成树在缩点之后一定是一个 \(n\) 个点的生成树.我们记 \(d_i\) 为第 \(i\) 个连通块缩完点之后的度数 \(-1\), ...

  4. HDU 3267 Graph Game(博弈论+图论+暴力)

    题面传送门 题意: 有一棵 \(n\) 个节点的图 \(G\),R 和 B 两个人轮流操作,R 先操作. 每次操作 R 可以染红任意一条未染色的边,B 可以染蓝任意一条未染色的边 R 的目标是染成一棵 ...

  5. nmap相关

    nmap -sT IP-sT(全链接扫描),获取目标IP+PORT的状态,其实是发了三个包:SYN,SYN/ACK,ACK,类似于TCP三次握手 状态: open 开放的 closed 关闭的 fil ...

  6. Oracle——检查数据库是否正常运行,如果没有,并重启数据库

    1.su oracle  切换到linux的oracle账号 需要使用 su -oracle,而不是su oracle;原因是: 先执行exit退出,再重新切换 2.打开数据库监听 lsnrctl l ...

  7. matplotlib 画饼图

    有个瑕疵,某一块儿比例过小时,文字会重叠. 1 def pizza(data,labs,title): 2 import matplotlib 3 import matplotlib.pyplot a ...

  8. 43-Reverse Nodes in k-Group

    Reverse Nodes in k-Group My Submissions QuestionEditorial Solution Total Accepted: 58690 Total Submi ...

  9. linux 网络配置管理

    [1]网络配置基础 (1)用户既可以通过命令行的方式,也可以通过友好的图形界面,轻松完成网络配置. (2)实现Linux网络配置的惟一目标就是修改系统中众多的网络配置文件, 如/etc/interfa ...

  10. 学习java 7.14

    学习内容: 标准输入输出流 输出语言的本质:是一个标准的输出流 字节打印流 字符打印流 对象序列化流 明天内容: 进程和线程 遇到问题: 用对象序列化流序列化一个对象后,假如我们修改了对象所属的类文件 ...