问题
如何正确进行对于依赖循环下标的赋值操作(形如
[i] = function() { /* use i */ }
)
描述
你有一个下标,你有一个函数,把它们合起来… 一般你会得到一堆错误…
为了能够顺利的避趋之,仅仅+1s是不够的,你需要更多的姿势…
真正的粉丝… 在代码运行前就能发现其中的Bug
为什么呢 Bug的第一个字母转90度试试…
代码
错误的姿势:
var arr = ['v1', 'v2', 'v3'];
for(var i = 0, funs = []; i < arr.length; ++i) {
funs[i] = function() { console.log(arr[i]); };
}
funs.forEach(function(e) { e(); });
// 此时你渴望得到的结果是...(奶子!)
// 依次输出v1 v2 v3 但其实结果是3个undefined
// 尝试一下输出 i; 你会发现此时 i=3; funs[3]是不存在的 所以结果为undefined
因为javascript的作用域规则导致i(坏…坏掉了)表现出奇怪的行为
此外还有一种比较常见的错误表现为,通过循环绑定的监听器触发的结果均为对最后绑定的监听器的触发行为
原因同上,当循环结束后i的值污染到了for循环外的作用域
为了杜绝这种现象的发生,你需要(去污粉!)借助一些手段…
正确的方法:
var arr = ['v1', 'v2', 'v3'];
for(var i = 0, funs = []; i < arr.length; ++i) {
funs[i] = (function(i) { return function() { console.log(arr[i]); }; })(i);
}
funs.forEach(function(e) { e(); });
// 貌似一下子就复杂了起来... (我有什么办法呢 我也很绝望啊)
// 但结果打到了预期的目标 依次输出了v1 v2 v3
看上去很复杂,我们分解开看:
1. 首先确认我们需要返回的东西
function() { console.log(arr[i]); }
2. 该函数依赖循环下标,为了使下标i脱离当前作用域,独立绑定到每一个功能逻辑部分,你需要IIFE
3.
(function(...args) { /* use args */ })(...args)
创建一个IIFE,传入需要脱离作用域的变量
4. 再其内部由于变量可见性,屏蔽了外部的同名变量,也就达到了改变指定变量作用域的作用
总结
使用
let
可以提早暴露这种问题,使用函数式思想也可以避免这种问题(我系map函数啦)
['v1', 'v2', 'v3'].map((e) => () => console.log(e)).forEach((f) => f());