以下是本人的一些看法,谢谢大家,欢迎砖头循环内使用闭包的其实要根据作用域来解释首先js中是没有“块状作用域”的,请看下面java例子
//scope1 作用域1
for (int i = 0; i < 10; i++){
//scope2 作用域2
String str = "123";
}
Systen.out.print(i);
Systen.out.print(str);
在有块状作用域的语言中,scope1与scope2是不同的作用域,所以
Systen.out.print(i);与Systen.out.print(str);都应该报错,i,str未定义
但js并没有块状作用域,看以下例子
//scope1 作用域1
for (var i = 0; i < 10; i++){
//scope2 作用域2
var str = "123";
}
alert(i);
alert(str);在js中scope1与scope2是同级的,所以alert(i)打印出10, alert(str)打印出123
不单for是这种情况,if,while等都是一样的,上面例子等同于//scope1 作用域1
var i = 0;
var str;
for (; i < 10; i++){
//scope2 作用域2
str = "123";
}
alert(i);
alert(str);
所以
//scope1 作用域1
var els = document.getElementsByTagName("li");
for (var i = 0, j = els.length; i < j; i++){
//scope2 作用域2
var el = els[i];
el.onclick = function(){
//scope3 作用域3
alert(i);
}
}
其实等同于//scope1 作用域1
var els = document.getElementsByTagName("li");
var i = 0, j = els.length; for (; i < j; i++){
//scope2 作用域2
var el = els[i];
el.onclick = fn;
} function fn(){
//scope3 作用域3
alert(i); //当执行onclick时,i已经循环完毕
}这时大家会想,scope3与scope1,scope2是不同一个作用域,为什么还能打印出来,
这是因为js有作用域链这种思想,当i在scope3找不到的时候,会向上级作用域scope1访问,如果类推,
直到scope1访问到,所以这里的i其实就是scope1中的i,这时i已经是循环完毕了。
因此要避免这种情况,我们就要从它的作用域入手了,请看改造例子//scope1 作用域1
var els = document.getElementsByTagName("li");
for (var i = 0, j = els.length; i < j; i++){
//scope2 作用域2
var el = els[i];
el.onclick = function(i){
//scope3 作用域3
return function(){
//scope4 作用域4
alert(i)
}
}(i)
}因为作用域链,alert(i)访问scope4没有,向上级scope3访问,它发现i已经由(i)传进来赋值了,
所以alert(i)这里的i其实是scope3作用域中的i,而并不是scope1中的i而如果我们改成这样
//scope1 作用域1
var els = document.getElementsByTagName("li");
for (var i = 0, j = els.length; i < j; i++){
//scope2 作用域2
var el = els[i];
el.onclick = function(){ //这里没有声明形参
//scope3 作用域3
return function(){
//scope4 作用域4
alert(i)
}
}(i)
}alert(i)中的i访问到的就是scope1的i,打印出来的还是循环完毕后的i...
//scope1 作用域1
for (int i = 0; i < 10; i++){
//scope2 作用域2
String str = "123";
}
Systen.out.print(i);
Systen.out.print(str);
在有块状作用域的语言中,scope1与scope2是不同的作用域,所以
Systen.out.print(i);与Systen.out.print(str);都应该报错,i,str未定义
但js并没有块状作用域,看以下例子
//scope1 作用域1
for (var i = 0; i < 10; i++){
//scope2 作用域2
var str = "123";
}
alert(i);
alert(str);在js中scope1与scope2是同级的,所以alert(i)打印出10, alert(str)打印出123
不单for是这种情况,if,while等都是一样的,上面例子等同于//scope1 作用域1
var i = 0;
var str;
for (; i < 10; i++){
//scope2 作用域2
str = "123";
}
alert(i);
alert(str);
所以
//scope1 作用域1
var els = document.getElementsByTagName("li");
for (var i = 0, j = els.length; i < j; i++){
//scope2 作用域2
var el = els[i];
el.onclick = function(){
//scope3 作用域3
alert(i);
}
}
其实等同于//scope1 作用域1
var els = document.getElementsByTagName("li");
var i = 0, j = els.length; for (; i < j; i++){
//scope2 作用域2
var el = els[i];
el.onclick = fn;
} function fn(){
//scope3 作用域3
alert(i); //当执行onclick时,i已经循环完毕
}这时大家会想,scope3与scope1,scope2是不同一个作用域,为什么还能打印出来,
这是因为js有作用域链这种思想,当i在scope3找不到的时候,会向上级作用域scope1访问,如果类推,
直到scope1访问到,所以这里的i其实就是scope1中的i,这时i已经是循环完毕了。
因此要避免这种情况,我们就要从它的作用域入手了,请看改造例子//scope1 作用域1
var els = document.getElementsByTagName("li");
for (var i = 0, j = els.length; i < j; i++){
//scope2 作用域2
var el = els[i];
el.onclick = function(i){
//scope3 作用域3
return function(){
//scope4 作用域4
alert(i)
}
}(i)
}因为作用域链,alert(i)访问scope4没有,向上级scope3访问,它发现i已经由(i)传进来赋值了,
所以alert(i)这里的i其实是scope3作用域中的i,而并不是scope1中的i而如果我们改成这样
//scope1 作用域1
var els = document.getElementsByTagName("li");
for (var i = 0, j = els.length; i < j; i++){
//scope2 作用域2
var el = els[i];
el.onclick = function(){ //这里没有声明形参
//scope3 作用域3
return function(){
//scope4 作用域4
alert(i)
}
}(i)
}alert(i)中的i访问到的就是scope1的i,打印出来的还是循环完毕后的i...
看了楼主说的后2段,还是说说俺的理解。
倒数第2段改为这样好理解一些:
el.onclick = function(k){
return function(){
alert(k)
}
}(i)说说俺的一些理解:
click右边应该是个functionHandle,绑定某个函数句柄,在之后的某个时刻才会触发调用这个函数。
function(){}()是立即执行这个函数。
return function(){}就是在这里返回一个functionHandle。
这就要理解值传递和引用传递了。。
给个例子var obj = {name: "123"}var fn = function(_obj){
return function(){
alert(_obj.name)
}
}(obj)obj.name = "222";fn(); //222
因为对象是引用传递的,再看var obj = 123;
var fn = function(_obj){
return function(){
alert(_obj)
}
}(obj)obj = "222";fn(); //123数值是值传递的~el.onclick = function(k){
return function(){
alert(k)
}
}(i)
这个就是与第二种情况一样,值传递~
我的压缩包里面不止一两样东西哦,那可是我学习和工作的所有资料,不管是学习还是工作都会需要。
http://download.csdn.net/user/yangtonghai