1:如何点击某一个 li 的时候 alert 输出其index?闭包
<ul id="test">函数
<li>111</li>this
<li>222</li>spa
<li>333</li>code
<li>444</li>对象
</ul>事件
window.onload = function(){作用域
var oLis = document.getElementById("test").getElementsByTagName("li");get
for(var i = 0;i < oLis.length;i ++){io
oLis[i].onclick = function(){
alert(i); //每次都是4
}
}
}
解析:由于在for循环里面指定给oLis[i].onclick的事件处理程序,也就是onclick那个匿名函数是在for循环执行完成后(用户点击时)才被调用的。而调用时,须要对变量i求值,解析程序首先会在事件处理程序内部查找,但i没有定义,而后又到方法外部查找,此时有定义,但i的值是4(只有i大于4才会中止执行for循环),所以,就会取到该值——这正是闭包(匿名函数)要使用其外部做用域中变量的结果。并且,这也是因为匿名函数自己没法传递参数(故而没法维护本身的做用域)形成的.(比较啰嗦,能够看下面的解释)
实际上是根据做用域链的原理,在这个函数里面的i其实引用的是最后一次i的值,为何不是0,1,2,3,...呢?由于在你for循环的时候,你并无执行这个函数,你这个函数是在你点击的时候才执行的,当执行这个函数的时候,它发现它本身没有这个变量i,因而向它的做用域链中查找这个变量i,由于当你单击这个box的时候已经for循环完了,因此储存在做用域链里面的i的值就是4,最后就弹出出来4了。
2:解决办法:将每次for循环中的变量i保存到某个地方;
方法一:
window.onload = function(){
var oLis = document.getElementById("test").getElementsByTagName("li");
for(var i = 0;i < oLis.length;i ++){
(function(i){
oLis[i].onclick = function(){
alert(i); //0123
}
})(i);
}
}
解释:成功打印每一个 i 的值,原理就是经过自执行函数,将变量i保存到这个自执行函数的参数中。
方法二:
window.onload = function(){
var oLis = document.getElementById("test").getElementsByTagName("li");
for(var i = 0;i < oLis.length;i ++){
oLis[i].index = i;
oLis[i].onclick = function(){
alert(this.index); //0123
}
}
}
解释:将每次循环获得的i,赋值给oLis[i]对象的index属性,在经过this指向,取出点击当前对象的index的值。
方法三:
window.onload = function(){
var oLis = document.getElementById("test").getElementsByTagName("li");
for(var i = 0;i < oLis.length;i ++){
oLis[i].onclick = (function(e){
return function(){
alert(e); //0123
}
})(i);
}
}
解释:
3:解决办法:让这个函数直接执行;
window.onload = function(){
var oLis = document.getElementById("test").getElementsByTagName("li");
for(var i = 0;i < oLis.length;i ++){
oLis[i].onclick = a();
function a(){
alert(i); /0123
}
}
}
解释:虽然这样能够打印出每次变量i的值,可是咱们没有点击li的时候他已经执行完了,也就是说,这个点击事件已经无关紧要了,因此咱们这种方法在绑定事件中不可用。
4:ES6为咱们新增了,定义变量的关键字 let
window.onload = function(){
var oLis = document.getElementById("test").getElementsByTagName("li");
for(let i = 0;i < oLis.length;i ++){
oLis[i].onclick = function(){
alert(i); //0123
}
}
}
解释:let
容许声明一个做用域被限制在块级中的变量、语句或者表达式。与var关键字不一样的是,它声明的变量只能是全局或者整个函数块的。
let的几点用法:
1>用于声明变量,不作变量提高;
2>在同一个做用域中,不容许重复声明同一个变量;
3>会产生块级做用域{ };
4>特殊注意:for循环是一个块级做用域,for后{}是一个块级做用域,for块级做用域是for{}块级做用域的父级做用域。
for(let i = 0;i < 5;i++,console.log( i )){ 0 1 2 3 4
let i = 10;console.log( i ); 10 10 10 10 10
}
alert(i);//报错
循环执行了几回,就存几个块级做用域,每个块级做用域都有一个变量 i ,可是这几个i不是同一个i 。(函数内部的变量i 与 循环变量i 不在同一个做用域,有各自单独的做用域)