问题再现

​ 最近开发中遇到一个问题,为什么每次输出都是5,而不是点击每个p,就alert出对应的1,2,3,4,5。

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>闭包演示</title>
</head>
<body>
<p>1</p>
<p>2</p>
<p>3</p>
<p>4</p>
<p>5</p>
<script type="text/javascript">
window.onload=function() {
var ps = document.getElementsByTagName("p");
for( var i=0; i<ps.length; i++ ) {
ps[i].onclick = function() {
alert(i);
}
}
}
</script>
</body>
</html>

此时点击任意p弹出的都是5

出现原因:js事件处理器在线程空闲时间不会运行,导致最后运行的时候输出的都是i最后的值,即:5


解决办法:使用闭包将变量i的值保护起来

//sava1:加一层闭包,i以函数参数形式传递给内层函数
for( var i=0; i<ps.length; i++ ) {
(function(arg){
ps[i].onclick = function() {
alert(arg);
};
})(i);//调用时参数
} //save2:加一层闭包,i以局部变量形式传递给内存函数
for( var i=0; i<ps.length; i++ ) {
(function () {
var temp = i;//调用时局部变量
ps[i].onclick = function() {
alert(temp);
}
})();
} //save3:加一层闭包,返回一个函数作为响应事件(注意与3的细微区别)
for( var i=0; i<ps.length; i++ ) {
ps[i].onclick = function(arg) {
return function() {//返回一个函数
alert(arg);
}
}(i);
} //save4:将变量 i 保存给在每个段落对象(p)上
for( var i=0; i<ps.length; i++ ) {
ps[i].i = i;
ps[i].onclick = function() {
alert(this.i);
}
} //save5:将变量 i 保存在匿名函数自身
for( var i=0; i<ps.length; i++ ) {
(ps[i].onclick = function() {
alert(arguments.callee.i);
}).i = i;
}
} //save6:用Function实现,实际上每产生一个函数实例就会产生一个闭包
for( var i=0; i<ps.length; i++ ) {
ps[i].onclick = new Function("alert(" + i + ");");//new一次就产生一个函数实例
} //save7:用Function实现,注意与6的区别
for( var i=0; i<ps.length; i++ ) {
ps[i].onclick = Function('alert('+i+')');
}

总结

在ECMAScript5和6中,var和let的作用域是不同的:var的作用域在函数上,let的作用域在块上,因此当有异步函数发生调用的时候,之前已经绑定好的点击事件会寻找在onload函数的i值,此时i值已经不是当初设定好的值,而是最后一次循环后的值,而使用let的话,那么在每次循环的时候就会在新的块上重新创建新的变量i,所以每次点击的i的值都会不同。

浅谈js for循环输出i为同一值的问题的更多相关文章

  1. 浅谈js for循环输出i为同一值的问题(闭包解决)

    1.最近开发中遇到一个问题,为什么每次输出都是5,而不是点击每个p,就alert出对应的1,2,3,4,5. <html> <head> <meta http-equiv ...

  2. 浅谈JS中的闭包

    浅谈JS中的闭包 在介绍闭包之前,我先介绍点JS的基础知识,下面的基础知识会充分的帮助你理解闭包.那么接下来先看下变量的作用域. 变量的作用域 变量共有两种,一种为全局变量,一种为局部变量.那么全局变 ...

  3. 浅谈 js 正则字面量 与 new RegExp 执行效率

    原文:浅谈 js 正则字面量 与 new RegExp 执行效率 前几天谈了正则匹配 js 字符串的问题:<js 正则学习小记之匹配字符串> 和 <js 正则学习小记之匹配字符串优化 ...

  4. 浅谈 js 字符串之神奇的转义

    原文:浅谈 js 字符串之神奇的转义 字符串在js里是非常常用的,但是你真的了解它么?翻阅<MDN String>就可以了解它的常见用法了,开门见山的就让你了解了字符串是怎么回事. 'st ...

  5. 浅谈 js 字符串 search 方法

    原文:浅谈 js 字符串 search 方法 这是一个很久以前的事情了,好像是安心兄弟在学习js的时候做的练习.具体记不清了,今天就来简单分析下 search 究竟是什么用的. 从字面意思理解,一个是 ...

  6. 浅谈JS中的!=、== 、!==、===的用法和区别 JS中Null与Undefined的区别 读取XML文件 获取路径的方式 C#中Cookie,Session,Application的用法与区别? c#反射 抽象工厂

    浅谈JS中的!=.== .!==.===的用法和区别   var num = 1;     var str = '1';     var test = 1;     test == num  //tr ...

  7. 浅谈JS中 var let const 变量声明

    浅谈JS中 var let const 变量声明 用var来声明变量会出现的问题: 1. 允许重复的变量声明:导致数据被覆盖 2. 变量提升:怪异的数据访问.闭包问题 3. 全局变量挂载到全局对象:全 ...

  8. 浅谈JS之AJAX

    0x00:什么是Ajax? Ajax是Asynchronous Javascript And Xml 的缩写(异步javascript及xml),Ajax是使用javascript在浏览器后台操作HT ...

  9. 浅谈 js 正则之 test 方法

    原文:浅谈 js 正则之 test 方法 其实我很少用这个,所以之前一直没注意这个问题,自从落叶那厮写了个变态的测试我才去看了下这东西.先来看个东西吧. var re = /\d/; console. ...

随机推荐

  1. 【奇淫巧技】sqlmap绕过过滤的tamper脚本分类汇总

    sqlmap绕过过滤的tamper脚本分类汇总

  2. 温故知新——C++--封装

      参考: 1.https://blog.csdn.net/cherrydreamsover/article/details/81942293 2.https://www.cnblogs.com/ji ...

  3. LiteOS-任务篇-源码分析-系统启动函数

    目录 前言 链接 参考 开启调度 LOS_Start 函数源码 osTickStart 函数源码 LOS_StartToRun 函数源码 前言 20201009 移植好内核后,开始实战内核. 源码分析 ...

  4. 动态枢轴网格使用MVC, AngularJS和WEB API 2

    下载shanuAngularMVCPivotGridS.zip - 2.7 MB 介绍 在本文中,我们将详细介绍如何使用AngularJS创建一个简单的MVC Pivot HTML网格.在我之前的文章 ...

  5. 应用启动失败,报错:The server experienced an unexpected error when processing the request

    前言 在腾讯云TKE集群中部署服务的时候,预警服务,warn一直重启,经过查询日志发现了如下的错误 The server experienced an unexpected error when pr ...

  6. 推荐Java字节码解析工具classpy

    Classpy Classpy is a GUI tool for investigating Java class file, Lua binary chunk, Wasm binary code, ...

  7. rxjs入门7之其它操作符复习

    一.辅助类操作符 二.过滤数据流 三.转化数据流 四.异常错误处理 五.多播 ,Subject类型

  8. Java安全之Javassist动态编程

    Java安全之Javassist动态编程 0x00 前言 在调试CC2链前先来填补知识盲区,先来了解一下Javassist具体的作用.在CC2链会用到Javassist以及PriorityQueue来 ...

  9. Oracle体系结构概述与SQL解析剖析

    Oracle服务器 是一个数据库管理系统,它提供了一种全面.开放.集成的方法来管理信息. Oracle服务器由Oracle数据库和Oracle实例组成. oracle数据库软件和Oracle数据库软件 ...

  10. 实验 4:Open vSwitch 实验——Mininet 中使用 OVS 命令

    一.实验目的 Mininet 安装之后,会连带安装 Open vSwitch,可以直接通过 Python 脚本调用Open vSwitch 命令,从而直接控制 Open vSwitch,通过实验了解调 ...