js循环添加onclick事件

来源:互联网 发布:算法导论 22.3 10 编辑:程序博客网 时间:2024/05/17 16:44

javascript在循环添加onclick事件时会出现函数传入参数均为最后一个值的问题,编写一个test.html如下所示:

<!doctype html><html lang="en"><head></head><body><input type='button' id='bt0' name='name1' value='0'/><input type='button' id='bt1' name='name2' value='1'/></body><script type='text/javascript'>for (var i=0;i<2 ;i++){var bt=document.getElementById('bt'+i);bt.onclick=function(){        console.log(i);//无论点击哪个按钮均打印2     };}</script></html>


了解javascript作用域机制的话。很容易看出问题出在哪里。循环结束后,i的作用域为windowscope,或者说i是全局变量,其值为2,click事件触发时显示的自然是2了。
为了解决这个问题,我们从onclick细细讲起

1.当我们点击一个button时,我们做了什么

让我们看看MDN中对onclick的解释

https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onclick

首先,onclick是button的一个属性,我们给这个属性赋值一个函数指针(function pointer),就完成了一个事件绑定,当click事件触发时就会进入这个function。

其次,这个函数指针到底是什么呢?再看看MDN中对onclick后面的function的解释


可以看到这个function既可以是函数声明,也可以是函数表达式。所谓函数表达式和函数声明的区别,举个栗子:var example=function(){}是函数表达式,function example(){}是函数声明。所以这个function有以下三种形式,我们通常用的第一种形式,即匿名函数形式,实际上是一个匿名的函数表达式。

document.getElementById('bt0').click=function(){  //匿名函数    console.log('example0');}var example1=function(){ //函数表达式    console.log('example1');};document.getElementById('bt1').click=example1;function example2(){ //函数声明   console.log('example2');}document.getElementById('bt2').click=example2;


这是没有参数传递的情况,若有参数呢?直接在函数指针里加参数?elemtent.onclick=example(parameter)的形式显然不行,因为这是调用函数了,会直接执行。但是可以在example()函数内部返回一个function。

2.在函数表达式或函数声明中返回一个function

点击button后,调用元素对应的onclick事件,解析程序在匿名函数内部找不到i,转而找到外部作用域的i,即为2,所以打印出2。归根到底,是由于element.onclick=function(){}等式右边的匿名函数无法传参而无法维护自己的作用域。(别想element.onclick=function(i){}这样传参,因为onclick事件默认的参数是event)。那么解决方法也就很容易想到了,不用匿名函数,而是以函数表达式或函数声明的形式传递参数,这就需要在函数内部返回一个function。

var clickEventExpression=function(arg){return function(){console.log(arg);}};function clickEventDeclaration(arg){return function(){console.log(arg);}}for (var i=0;i<2 ;i++){var bt=document.getElementById('bt'+i);bt.onclick=clickEventExpression(i);//or bt.onclick=clickEventDeclaration(i)}


3.闭包

或者换个思路,仍用匿名函数,不过要在匿名函数内部产生一个可以自己维护的作用域,来保存变量i。咦,好熟悉的概念,这不就是闭包嘛。

“闭包就是将所有自由变量和函数绑定在一个封闭的表达式中,这个表达式可以保留在自由变量和函数创建之外的词法作用域。”这里我们用(function{})()形式的立即执行函数来创建一个封闭的表达式。

//加一层闭包,i 以局部变量形式传递给内层函数for (var i=0;i<2 ;i++){    (function(){        var bt=document.getElementById('bt'+i);var temp=i;        bt.onclick=function(e){            console.log(temp);        }    })();}

或者

//加一层闭包,i以函数参数形式传递给内层函数for (var i=0;i<2 ;i++){      var bt=document.getElementById('bt'+i);    bt.onclick=(function(arg){        return function(){            console.log(arg);            };    })(i);}


4.let 和const

let和const的声明可以产生块级作用域,同样可以解决我们的问题。

for (var i=0;i<2 ;i++){let ii=i;//const也可以,块级作用域var bt=document.getElementById('bt'+ii);bt.onclick=function(){console.log(ii);};}



                                             
1 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 带欣的名字三个字儿的怎么办 二十多岁的儿子沉迷游戏网络怎么办 为什么打开游戏网络却用不了怎么办 打来微信网页版显示证书错误怎么办 开了家定制家具店生意不好怎么办 宝宝起风疹怎么办要注意的问题 超市买的内裤西铁牌子没去掉怎么办 没申请生产许可证贴标了怎么办 淘宝没有品牌非要我写品牌怎么办没 意外怀孕明明一直用安全套的怎么办 找不到百度网盘的dns地址怎么办 小米众筹到了发货时间不发货怎么办 不知道电脑宽带连接账号密码怎么办 电脑如果宽带账号密码忘记了怎么办 xp电脑用户名和密码忘了怎么办 电脑的用户名和密码忘记了怎么办 电脑重置后需要用户名和密码怎么办 电脑登录用户名和密码忘记了怎么办 电脑登录用户名和密码忘了怎么办啊 微信无意中点了允许登录怎么办 qq号码登录微信无法验证怎么办 注册微信公众号邮箱激活不了怎么办 不是自己申请的qq号忘密码怎么办 联通宽带拨号账号密码忘记了怎么办 忘了路由器的用户名和密码怎么办 宽带连接用户名和密码忘了怎么办 江西银行网银用户名忘记了怎么办 江西银行网银密码忘了怎么办 广发信用卡网银密码忘了怎么办 刚注册的淘宝账号买不了东西怎么办 隐藏后的wif不知道用户名怎么办 脊柱侧弯术后钢钉断了一根怎么办 对法院执行裁定申请复议过期怎么办 自己家店名被别人注册了商标怎么办 有人去工商局投诉我公司了怎么办 急用钱怎么办啊有没有什么贷款啊 初级会计报名信息表没打印怎么办 电工证复审流程时间过了怎么办 应版权方要求无法下载的电影怎么办 手机设置蜜码小孩都能破解该怎么办 拍到了上海车牌不想买车了怎么办