今天在查看网上淡入淡出的轮播原代码时,有一些不明白的地方
function addEvent(){
for(var i=0;i<otxtLen;i++){
(function(_i){
oBtn[_i].onclick=function(){
clearTimeout(autoChange);
changeTo(_i);//这是调用开始轮播的变换函数
curIndex=_i;
autoChange=setInterval(function(){
if(curIndex<otxtLen-1){
curIndex++;
}
else{
curIndex=0;
}
changeTo(curIndex);
},2500);
}
})(i);
}
}
问题1:
这个(_i)
传进去的值是for循环的i吗?
我试着把(_i)
改成(i)
,运行起来也是没有问题。
问题2:
什么for循环里面的function要用圆括号包起来?结尾有一个(i)
是做什么用的呢?
问题3:
代码中clearTimeout(autoChange);
为什么setInterval可以用clearTimeout来关闭?
麻烦各位朋友帮忙解决下小弟的困惑,万分感谢!!!
PHP中文网2017-04-10 17:08:05
問題1 _i
是 for 的 i 帶入的沒錯不過更嚴格地說是 IIFE 立即函式就下面那個 i 傳入的,_i 應該是為了避免疑義。
問題2
思考一下下面這個簡化的例子
var funcs = [];
for (var i = 0; i < 10; i++) {
funcs[i] = function () {
console.log(i); // 當你的 event 需要 i 時
}
}
funcs[0](); // 預計是 0 但輸出是 10
var funcs = [];
for (var i = 0; i < 10; i++) {
(function (i) {
funcs[i] = function () {
console.log(i); // 當你的 event 需要 i 時
}
})(i);
}
funcs[0](); // 就是 0 了
原理就是利用閉包去保留 context 我推薦這篇寫的挺詳細的。
問題3
參考這篇
第二則回答從 w3c 定義推論出他們是一樣的。可以視為同意。
不過我暫時比較接受第一個答案不應該互通,不過事實是大部分瀏覽器實作上是共用 timer 清除,所以可把它們視為同意,但不該認為兩者就沒有差別。
看看w3c自己的範例都用了(搜尋 clearTimout 看範例)我能說什麼呢!?
PHPz2017-04-10 17:08:05
问题1
行为是一样的, 因为每次循环时的匿名函数都是新的scope, 不影响for那个scope中的变量i. 专门用不同的变量名可能是为了好读.
问题2(function(){})(i)
是函数调用, 这种定义一个匿名函数然后立刻调用的写法叫IIFE.
IIFE经常是为了创建scope, 即把每次循环时i的值绑定到一个新的变量: 每次创建的匿名函数都有一个_i变量, 这个_i的值固定为匿名函数创建时的i的值. 就算i后来变掉也没影响.
问题3
我也不知道为什么...标准好像不应该可以这样做, 不过有的浏览器中clearInterval和clearTimout真的可以互换.
伊谢尔伦2017-04-10 17:08:05
_i是函数的形参
这是for循环中的经典闭包,后面的(i)是实参
个人认为是错的,应该是clearInterval。具体是否可以用clearTimeout来替代,不确定。
伊谢尔伦2017-04-10 17:08:05
最典型的闭包问题,可以看看阮一峰或者司徒正美的文章,举得都是这种例子,如果你不用闭包实现的话,这里不同按钮上绑定的函数在点击后调用的函数中i为同一个值,明显不是本意。