首页 > 试题广场 > 依次点击4个li标签,哪一个选项是正确的运行结果()?
[单选题]
现有如下html结构
<ul>
 <li>click me</li>
 <li>click me</li>
 <li>click me</li>
 <li>click me</li>
</ul>
运行如下代码:
    var elements=document.getElementsByTagName('li');
    var length=elements.length;
    for(var i=0;i<length;i++){
        elements[i].onclick=function(){
        alert(i);
    }
 }
依次点击4个li标签,哪一个选项是正确的运行结果()?
  • 依次弹出1,2,3,4
  • 依次弹出0,1,2,3
  • 依次弹出3,3,3,3
  • 依次弹出4,4,4,4
说白了,i就是点击获取i的值,但是i是变量,循环结束了i的结果是4,所以点击后肯定弹出4
发表于 2019-02-18 13:00:18 回复(0)
更多回答
推荐
M.J头像 M.J
D

因点击为匿名函数,其执行到这里的时候 i 已是 4,即不会改变~
编辑于 2015-01-27 10:27:36 回复(16)
我来一个专业解释吧:这里考的是JS的运行机制! 事件(click,focus等等),定时器(setTimeout和setInterval),ajax,都是会触发异步,属于异步任务;js是单线程的,一个时间点只能做一件事,优先处理同步任务; 按照代码从上往下执行,遇到异步,就挂起,放到异步任务里,继续执行同步任务,只有同步任务执行完了,才去看看有没有异步任务,然后再按照顺序执行! 这里for循环是同步任务,onclick是异步任务,所以等for循环执行完了,i变成4了,注意:这里因为i是全局变量,最后一个i++,使得i为4(后面的onclick函数,最后在循环外面执行,不受i<length限制); 所以for循环每执行一次,onclick事件函数都会被挂起一次,共4次; for循环结束后,点击事件 触发了4个onclick函数,接着输出4个4! 对大家有用的话,希望点个赞👍!
发表于 2017-10-17 12:55:32 回复(30)
我的理解是:每个li标签的onclick事件执行时,本身onclick绑定的function的作用域中没有变量i,i为undefined,则解析引擎会寻找父级作用域,发现父级作用域中有i,且for循环绑定事件结束后,i已经赋值为4,所以每个li标签的onclick事件执行时,alert的都是父作用域中的i,也就是4。这是作用域的问题。
编辑于 2015-08-20 21:48:27 回复(30)
//权威解答——来自javascript语言精粹
var elements=document.getElementsByTagName('li');
    var length=elements.length;
    for(var i=0;i<length;i++){
        elements[i].onclick=function(){
        alert(i);
    }
 }
        解答:这里的事件,绑定的并非是i的值,而是i本身(alert里的i),所以当程序执行完,i的值变为4,去执行onclick事件时,执行alert(i) ,自动查找i,值为4,所以依次弹出4。
        改正:
var elements=document.getElementsByTagName('li');
    var length=elements.length;
    var handler = function(i){
        return fucntion(){
            alert(i);
        }
    }
    for(var i=0;i<length;i++){
        elements[i].onclick= handler(i);
 }
避免在循环中创建函数,可以在循环之外创建一个辅助函数,让这个辅助函数返回一个绑定了当前i值得函数,避免混淆

发表于 2016-01-28 11:02:04 回复(12)

编辑于 2016-08-28 15:48:14 回复(2)
(《JavaScript高级程序设计》解释:)这是由于作用域链的这种配置机制引出的一个副作用,即闭包只能取得包含函数中任何变量的最后一个值。闭包所保存的是整个变量对象,而不是某个特殊的变量。
这里的闭包函数elements[i].onclick=function(){alert(i);}
的作用域链中保存着闭包的活动对象(这里为空)和全局变量对象(主要是i),
所以,它们引用的是同一个变量i;当点击完成后,变量i=4,也就是每个内部函数i的值都是4;
可以通过创建另一个匿名函数强制让闭包的行为符合预期:

window.onload  = function() {
    var elements=document.getElementsByTagName('li');
    var length=elements.length;
    for(var i=0;i<length;i++){
        elements[i].onclick=function(num){
	    return function() {
    	        alert(num);
	    };
	}(i);
    }
}
    
在调用匿名函数时,我们传入变量i,由于参数是按值传递的,所以就会将变量i的当前值复制给参数num。而这个匿名函数内部,又创建并alert了一个访问num的闭包。这样,每一次点击都有num变量的一个副本,因此可以返回各自不同的数值。
发表于 2016-09-17 00:36:05 回复(4)
页面加载后会自动把脚本部分执行,执行完脚本,i=4. 当点击click me时 触发onclick事件 此时的i早已是4
发表于 2015-03-27 13:30:35 回复(3)
闭包
(1)概念
闭包是指有权访问另一个函数作用域中的变量的函数。
(2)特性
闭包只能取得包含函数中任何变量的最后一个值。
(3)创建方式
在一个函数内部创建另一个函数。
(4)原理
在一个函数内部中定义的函数会将包含函数(外部函数)的活动对象添加到其作用域中,直至解除对内部函数的应用,内部函数被销毁,外部函数的活动对象才会被销毁。
(5)实例
function closure(){
    var result=[];
    for (var i = 0; i < 4; i++) {
        result[i]=function(){
            console.log(i);
            return i;
        }
    };
    return result;
}
var result=closure();
for (var i = 0; i < 4; i++) {
    result[i]();
};
4 4 4 4
发表于 2016-07-29 11:12:49 回复(5)
for循环有一个自己的小小作用域,每执行一次,只是将function赋给onclick事件,和函数内的内容无多大关系。最后点击时触发执行,此时的i已经为4,所以全部为4.该处重点理解  将函数当成一个数据类型,每循环一次相当于赋与函数一次,并未执行  
发表于 2015-10-29 13:58:05 回复(1)
var elements=document.getElementsByTagName('li');
    var length=elements.length;
    for(var i=0;i<length;i++){
        elements[i].onclick=(function(a){
            return function(){
            alert(a);
            }          
        })(i);
    }
//用此代码可以依次弹出 0,1,2,3(闭包可以“包养”外部函数变量)
编辑于 2015-08-17 16:49:10 回复(6)
建议去看一下JavaScript高级程序设计的函数闭包那一节  讲的很深刻



发表于 2017-04-10 21:48:07 回复(1)
页面加载后会自动把脚本部分执行,执行完脚本,i=4,当点击click me 时触发onclick事件,此时的i早已经是4了。
发表于 2015-08-26 17:28:14 回复(0)
个人理解:这个题涉及到了作用域链,在函数内部要alert(i)但是函数中并没有变量i,此时只能延伸作用域链,向上一级去找。此时for循环已经执行完毕,因为最后是i++,所以结果是4;最终输出的都是4。然而仍存在疑问:为啥到上一层找的时候for循环就已经执行完毕了呢?
别人的解读:还涉及到了JS的运行机制:事件(click,focus等),定时器(setTimeout,setInterval),ajax都会触发异步,属于异步任务;JS是单线程的,一个时间只能做到一件事,有先处理同步任务,然后再按照顺序执行。这里for循环是同步任务,onclick是异步任务,所以等for循环执行完了,i变成了4。(这个就解决了为什么到上一层找 i 的时候for循环就已经执行完毕了)。
发表于 2019-04-11 23:55:03 回复(0)

这道题涉及到javascript的一个大坑,没有块级作用域。这里面的i实际是全局变量,所以最好显示是4 4 4 4。如果把for循环中的var i 改成 let i,就可以正确显示0 1 2 3了

发表于 2018-08-12 11:11:08 回复(0)
js没有块级作用域,所以 变量i是全局变量。 在点击事件发生之前,匿名函数没有被调用,所以for循环会执行完,(i=3,i++,i=4) 点击事件发生,for循环执行,调用匿名函数 ,弹出窗口. i=4
编辑于 2016-06-24 13:24:41 回复(0)
闭包问题,点击相当于调用了其中的闭包函数,闭包把i保存在作用域链中,同一个作用域中的不同闭包共用这个i,所以返回i最后保存的值
发表于 2016-05-04 10:46:04 回复(0)
仔细看代码就明白,不是点一次触发一次循环,而是即使不触发onclick,for循环已经走完了,当触发时alert出的i肯定就是最终值了,而因为跳出循环的前提条件必定是i=4才能跳出来,所以不选C,选D
发表于 2018-03-16 15:03:43 回复(0)
function(){
        alert(i);
}
在这个function里并没有定义i,所以就会沿着作用域链向外查找父级有没有i。而在全局作用域中, for(var i=0;i<length;i++) 循环已经执行完毕了,i为最后一个4了,所以click后,都会alert出4咯~
发表于 2017-03-26 11:50:05 回复(0)
闭包 (1)概念 闭包是指有权访问另一个函数作用域中的变量的函数。 (2)特性 闭包只能取得包含函数中任何变量的最后一个值。 (3)创建方式 在一个函数内部创建另一个函数。 (4)原理 在一个函数内部中定义的函数会将包含函数(外部函数)的活动对象添加到其作用域中,直至解除对内部函数的应用,内部函数被销毁,外部函数的活动对象才会被销毁。 (5)实例 function closure(){     var result=[];     for (var i = 0; i < 4; i++) {         result[i]=function(){             console.log(i);             return i;         }     };     return result; } var result=closure(); for (var i = 0; i < 4; i++) {     result[i](); }; 4 4 4 4
发表于 2017-03-07 20:01:19 回复(0)
<script>
var elements = document.getElementsByTagName("li");
    var length = elements.length;
for(var i = 1; i < length+1; i++){
    elements[i-1].index = i;    //index 属性可返回下拉列表中选项的索引位置。
   elements[i-1].onclick = function(){
                alert(this.index);
    }
        }
</script>
该题猛一看没毛病,就应该点第几个弹第几个。其实,for循环中的点击事件,每次点击返回的都是i循环完成的值。如果想得到想要的效果,就要每次循环都把i保存下来,然后每次点击的时候,都是想要的值了。------> index 属性可返回下拉列表中选项的索引位置。
发表于 2016-09-28 11:01:37 回复(0)
我觉得其实这个可以看成是一个闭包,事件函数中没有变量i,因此到作用域链上找,在上一级作用域中找到了i。至于为什么此时的i值为4,是因为只有当js加载解析好了之后,li才添加了点击事件,则此时i必然为4
发表于 2016-01-14 20:38:33 回复(0)