从一个基础Javascript面试题谈起
记得第一次面试前端工程师的时候,面试官出了一个机试题,要求每个p单击时弹出不同的值,我是这么写的,执行的时候发现每次都是alert(5),当时坚持认为我的代码没有任何问题,心想这么简单的功能我怎么会弄错。时至今日,想起这件事,便写篇博文总结之。
<!DOCTYPE HTML> <html> <head> <meta charset="utf-8" /> <title>面试试题</title> <script type="text/javascript"> function init() { var pArr = document.getElementsByTagName("p"); for( var i=0; i<pArr.length; i++ ) { pArr[i].onclick = function() { alert(i); } } } </script> </head> <body onload="init();"> <p>段落1</p> <p>断落</p> <p>段落3</p> <p>段落4</p> <p>段落5</p> </body> </html>
执行以上的代码,会发现一个有趣的现象,每次单击p时弹出的结果都是5,究竟为什么呢,而不是0,1,2,3,4?我想发表一下个人见解:
以上代码是在onload的时候执行了init方法,即已经为每个P添加了单击事件监听,当我们单击P时,其实i的值此时已经是5了(这其实是一个程序执行的时间问题,在我们单击P之前,循环已经执行完毕,i的值最后变成了5退出了循环,如果我们可以做到在一个p添加单击时间之后和下一个p添加单击事件之前单击p的话,肯定得到的是0,1,2,3,4这样的结果,但是我们的速度不可能超过程序执行的速度,所以循环执行完后,i其实最后是5了,我们以后的单击都会alert(5),不知各位看官理解了没有)。
如果我们想每次单击都alert不同的值,我们可以参考下面这个简单可行的方法:
function init() { var pArr = document.getElementsByTagName("p"); for( var i=0; i<pArr.length; i++ ) { pArr[i].i=i; pArr[i].onclick = function() { alert(this.i); } } }
我们可以在循环添加单击事件时,将i的值存放到p里面(因为p是一个DOM对象,既然是对象,就可以添加属性和方法,这里我们为p添加一个属性i,赋值为i),最后我们每次单击p的时候alert的总是p[i]的属性值。