- 0
- 1
- 2
- 3
var nodeList = document.getElementsByTagName('li');
for(var i = 0;i < nodeList.length;i++){
nodeList[i].onclick = function(){
console.log(i);
}
}
这里每个li的onclick触发后 都会输出4 ,因为console.log(i)只是对i变量的引用
如果改成一下代码:
for(var i = 0;i < nodeList.length;i++){
nodeList[i].num = i;
nodeList[i].onclick = function(){
console.log(this.num);
}
}
可以正常输出0,1,2,3 猜测原因是在为li创建onclick事件的同时创建属性num
所以num和onclick都是属于li的一部分,那么再变化一下代码
for(var i = 0;i < nodeList.length;i++){
var num = i;
nodeList[i].onclick = function(){
console.log(num);
}
}
这里依然会输出4,如果说是因为引用了num,而num又引用了i
那么,为什么以nodeList[i].num = i 的可行?
为li创建了属性num的同时
nodeList[i].num = i 算是对i的引用还是赋值?
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号
你这样的学习方法真的太可怕啦!.
闭包会都输出4的原因是, 函数定义时并不执行.
之所以输出的全部是3, 是因为li绑定的事件处理函数在定义时并未执行, 当你触发li的点击事件时函数执行, 此时的i是3,当然会输出3.
为li增加一个属性, 为num属性赋值是在什么时候发生的? 他并没有放到函数里, 所以这个语句直接就执行啦. 此时i就分别为0,1,2,3, 等事件处理函数执行的时候, 输出的是对应li的num值, 而这个时候的num已经在上一步就为其赋值啦. 当然会输出0,1,2,3
这个是因为, num变量被覆盖了值.
假设代码改成这样:
你说他会输出什么?
有趣的问题,我来回答参考一下。
第一个代码一定会是4,原因是
console.log在执行时,并不会记住在过程中的i值。onclick后面指的是个回调函式,所以相等于下面更明确的改写:
为何要把
var i;独立出来,因为在这里for中所宣告的i,相当于在全域中宣告。另一个console.log也是,它是个回调函式,没执行(没按下去触发)不会呼叫的。所以当console.log真正被执行时,这个时候i老早就经过跳出for语句,变成了4。第二例是这样:
这回改用
nodeList[i].num属性先接好每次for运算的i值,相当有用,然后也知道要用this值传给console.log作输出。我假设你知道了几件事:
你知道
getElementsByTagName的回传是什么,也就是如上面所看起来你用了像阵列的用法这样。nodeList[i].num这样的用法,是在物件中新增属性console.log(this.num),这边的this是代表什么意思,对象是谁你的猜测是正确的: 猜测原因是在为li创建onclick事件的同时创建属性num,所以num和onclick都是属于li的一部分。
来看第三个例,最后再说明我的看法。
在第三例中,你会认为var num的效果会和第二例的
nodeList[i].num与this.num的用法一致,所以这样用。实际上并没有,它与和第一例是一样的。所以我也猜测你可能在第二例中,不知道在作什么,所以我以下要说明一下。
什么时候是引用,什么时候是赋值?
num = i;、var i = 0这个叫赋值,nodeList[i].num = i;这个也叫赋值,JavaScript基本上看到等号(=)的都是值传递。只有几种情况会看到所谓的"引用"(参照),第二例有个,就是this引用(指向)到元素物件。然后console.log()只是个函式,你当下给他什么值作为传参,他就输出在控制台中,就这样,没什么引不引用。
你用了很多不好的语法
第一个是,
nodeList[i].num = i;就是个,nodeList[i]的确是个物件,但原先没有的东西你生了一个给他,这个作法不是很好,也没见人这样用的。元素(Element)的话可以加上data-开头之类的属性,有API可套用,不过这是HTML5的标准。你这里应该是NodeList与Node物件,详细要看API说明。第二个是你在for语句里宣告
var num = i;,for语句里不就执行4次就宣告4次?我当然知道js引擎都会优化,所以这是个不好的语法。要不就写到for(var i = 0, num = 0;...,要不然就先在for语句外面宣告。接著我要说明如何改进你的代码,让它可以达到你想要的,以下是几个范例:
第一种: 用
bind产生新函式,然后指定给onclick:第二种:用IIFE,然后回传新函式:
上面两例用的技术类似,其实都先锁住
console.log只能输出什么了。差不多这样,搞得太复杂可能又有太多疑问。