浅谈js for循环输出i为同一值的问题
问题再现
最近开发中遇到一个问题,为什么每次输出都是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为同一值的问题的更多相关文章
- 浅谈js for循环输出i为同一值的问题(闭包解决)
1.最近开发中遇到一个问题,为什么每次输出都是5,而不是点击每个p,就alert出对应的1,2,3,4,5. <html> <head> <meta http-equiv ...
- 浅谈JS中的闭包
浅谈JS中的闭包 在介绍闭包之前,我先介绍点JS的基础知识,下面的基础知识会充分的帮助你理解闭包.那么接下来先看下变量的作用域. 变量的作用域 变量共有两种,一种为全局变量,一种为局部变量.那么全局变 ...
- 浅谈 js 正则字面量 与 new RegExp 执行效率
原文:浅谈 js 正则字面量 与 new RegExp 执行效率 前几天谈了正则匹配 js 字符串的问题:<js 正则学习小记之匹配字符串> 和 <js 正则学习小记之匹配字符串优化 ...
- 浅谈 js 字符串之神奇的转义
原文:浅谈 js 字符串之神奇的转义 字符串在js里是非常常用的,但是你真的了解它么?翻阅<MDN String>就可以了解它的常见用法了,开门见山的就让你了解了字符串是怎么回事. 'st ...
- 浅谈 js 字符串 search 方法
原文:浅谈 js 字符串 search 方法 这是一个很久以前的事情了,好像是安心兄弟在学习js的时候做的练习.具体记不清了,今天就来简单分析下 search 究竟是什么用的. 从字面意思理解,一个是 ...
- 浅谈JS中的!=、== 、!==、===的用法和区别 JS中Null与Undefined的区别 读取XML文件 获取路径的方式 C#中Cookie,Session,Application的用法与区别? c#反射 抽象工厂
浅谈JS中的!=.== .!==.===的用法和区别 var num = 1; var str = '1'; var test = 1; test == num //tr ...
- 浅谈JS中 var let const 变量声明
浅谈JS中 var let const 变量声明 用var来声明变量会出现的问题: 1. 允许重复的变量声明:导致数据被覆盖 2. 变量提升:怪异的数据访问.闭包问题 3. 全局变量挂载到全局对象:全 ...
- 浅谈JS之AJAX
0x00:什么是Ajax? Ajax是Asynchronous Javascript And Xml 的缩写(异步javascript及xml),Ajax是使用javascript在浏览器后台操作HT ...
- 浅谈 js 正则之 test 方法
原文:浅谈 js 正则之 test 方法 其实我很少用这个,所以之前一直没注意这个问题,自从落叶那厮写了个变态的测试我才去看了下这东西.先来看个东西吧. var re = /\d/; console. ...
随机推荐
- 03 以Hello World为例,分析C语言的最小的程序结构
C程序主要包含的部分 预处理器指令 函数 变量 语句 & 表达式 注释 C Hello World 实例 如下程序,可以在屏幕输出短句"Hello World" #incl ...
- [学习笔记] Tarjan算法求桥和割点
在之前的博客中我们已经介绍了如何用Tarjan算法求有向图中的强连通分量,而今天我们要谈的Tarjan求桥.割点,也是和上篇有博客有类似之处的. 关于桥和割点: 桥:在一个有向图中,如果删去一条边,而 ...
- 多测师讲解pthon_re模块_高级讲师肖sir
#import re 一.我们就re模块(也叫正则模块)介绍: 实现一个编译查找,一般在日志处理或者文件处理时用的比较多 正则表达式主要用于模式匹配和替换工作. 预定义字符集匹配: \d: ...
- linq 整理(前序)
前言 对linq进行整理,分为前序.中序和后序. 前序就是一些简单的概念和模拟. 中序的话就是深挖一些思想. 后序对其进行解刨. 正文 语言集成查询 (LINQ) 是一系列直接将查询功能集成到 C# ...
- 题解:POI2012 Salaries
题解:POI2012 Salaries Description The Byteotian Software Corporation (BSC) has \(n\) employees. In BSC ...
- [Leetcode题解]2. 两数相加-链表遍历和重构
1. 审题leetcode 02 add-two-numbers 我们先看一下题目,如下 : 链表的从前往后为数字的低位到高位,模拟加法手算过程,从前往后遍历即可, 注意每个数字0-9,进位要处理 ...
- ansible使用shell模块在受控机上执行命令(ansible2.9.5)
一,ansible的shell模块和command模块的区别? shell模块:在远程主机上执行主控端发出的shell/python脚本 command模块:不能调用shell指令,没有bash的环境 ...
- 说明资源路径位置类型无法解析The type javax.servlet.http.HttpServletResponse cannot be resolved.
导入dispatch项目后报错: 解决办法:在项目上单击鼠标右键> Add Libraries 选择 Server Runtime,下一步 选中Apache Tomcat7 完成 切换标 ...
- visio2016激活 试用版
输入秘钥: W9WC2-JN9W2-H4CBV-24QR7-M4HB8 可以成功激活成试用版 有效期30天,30天之后需要你正式激活! 经本人使用完全可以激活,欢迎大家使用! 也欢迎大家支持正 ...
- 3.QOpenGLWidget-通过着色器来渲染渐变三角形
在上章2.通过QOpenGLWidget绘制三角形,我们学习绘制三角形还是单色的,本章将为三角形每个顶点着色. 1.着色器描述 着色器的开头总是要声明版本,接着是输入和输出变量.uniform和m ...