一、for循环中使用var常会遇到的问题
直接上代码:
// 使用var声明,得到3个3
var a = [];
for (var i = 0; i < 3; i++) {
a[i] = function () {
console.log(i);
};
}
a[0](); //3
a[1](); //3
a[2](); //3
//使用let声明,得到0,1,2
var a = [];
for (let i = 0; i < 3; i++) {
a[i] = function () {
console.log(i);
};
}
a[0](); //0
a[1](); //1
a[2](); //2
如果上述a[i]函数是点击div[i]事件,那使用var的话会连续点击 div[2] 3次,使用let的话会依次点击 div[0]、div[1]、div[2]。
二、拆解
首先,我们得知道for循环是怎么执行的。对于一个for循环,设置循环变量的地方是一个父作用域,而循环体代码在一个子作用域内;for循环还有条件判断,与循环变量的自增。
for循序的执行顺序是这样的:设置循环变量(var i = 0) ==》循环判断(i<3) ==》满足执行循环体 ==》循环变量自增(i++)
我们按照这个逻辑改写上面的for循环,以第一个var声明为例,结合父子作用域的特点,上面的代码可以拆解如下:
- 声明为var情况
{
//我是父作用域
var i = 0;
if (0 < 3) {
a[0] = function () {
//我是子作用域
console.log(i);
};
};
i++; //为1
if (1 < 3) {
a[1] = function () {
console.log(i);
};
};
i++; //为2
if (2 < 3) {
a[2] = function () {
console.log(i);
};
};
i++; //为3
// 跳出循环
}
//调用N次指向都是最终的3
a[0](); //3
a[1](); //3
a[2](); //3
- 声明为let情况(其实是模拟了let的作用域)
var a = [];
{
//我是父作用域
let i = 0;
if (i < 3) {
//这一步模拟底层实现
let k = i;
a[k] = function () {
//我是子作用域
console.log(k);
};
};
i++; //为1
if (i < 3) {
let k = i;
a[k] = function () {
console.log(k);
};
};
i++; //为2
if (i < 3) {
let k = i;
a[k] = function () {
console.log(k);
};
};
i++; //为3
// 跳出循环
}
a[0](); //0
a[1](); //1
a[2](); //2
【前端-开发环境】使用NVM实现不同nodejs版本的自由切换(NVM完整安装使用手册)
【前端-NPM私服】内网使用verdaccio搭建私有npm服务器
【前端-IE兼容】Win10和Win11使用Edge调试前端兼容IE6、IE7、IE8、IE9、IE10、IE11问题
【工具-Shell脚本】java程序产品包模板-linux和windows通用shell启动停止脚本(无需系统安装Java运行环境)
【工具-Nginx】Nginx高性能通用配置文件-注释版-支持防刷限流、可控高并发、HTTP2、防XSS、Gzip、OCSP Stapling、负载、SSL
【工具-WireShark】网络HTTP抓包使用教程
【后端-maven打包】通过profile标签解决同时打jar包 war包需求
【后端-SpringCache】基于Spring Cache封装一个能够批量操作的Redis缓存记录下踩坑历程(pipeline或mget封装)
【后端-SkyWalking】SkyWalking前后端开发环境搭建详细教程步骤-6.x/7.x/8.x版本通用-插件二次开发利器(一)
✨欢迎为耿直少年点赞、关注、收藏!!!
👇👇👇