总结下最近在写的项目中遇到的一个小问题:
Mutable variable is accessible from closure
问题的解决办法涉及到 JavaScript 的闭包
及匿名自执行函数
,关于什么是闭包
并不像知乎上各位大神的“通俗解释”那样难理解,看一篇方应行的JS中的闭包是什么?就足够了。接下来,详细说说我所遇到的问题及解决办法
我在项目中写了下面这段代码:
这段代码的目的是使用循环给多个元素绑定点击事件,看起来好似完全没问题,但测试时却发现并没有成功给元素绑定点击事件,这时我注意到了在 IDEA
回调函数中的变量 i
颜色和其他的 i
颜色不同,鼠标悬浮在该变量上, IDEA
提示如下:
Mutable variable is accessible from closure.
Checks for accessing mutable JavaScript variables in nested function. The validation works in JavaScript, html, or jsp files.
重点在第一句,意思就是在提示我们循环变量 i
可以从 闭包
中访问,这个提示看的我一脸茫然,但最终在 Stack Overflow
上找到了答案:
Mutable variable is accessible from closure
How to avoid access mutable variable from closure
Mutable variable is accessible from closure. How can I fix this?
原来是因为我绑定的回调函数只有在点击元素时才会调用,而此时 for 循环早已执行完毕,回调函数中并没有拿到循环中正确的变量 i
,也就是说我遇到了循环和异步调用的经典问题,同时这也是闭包的经典作用之一
解决办法是使用闭包来保存变量,这样即使 i
一直在变,但闭包中使用 index
变量保存了变量 i
的值,回调函数就可以拿到正确的下标了,所以,最终我把代码改成了如下形式
|
当然为了传参你也可以把匿名自执行函数写成如下形式,详见js中的匿名函数和匿名自执行函数
function clickImageIcon(msgArr, options) { for (var i = 0; i < msgArr.length; i ++) { (function(index) { $('.file-wrapper:eq(' + index + ')').bind('click', function () { recognitionContent(msgArr[index]); $('#myModal').modal(options); }); })(i); } } |
|
如果你使用 ES6
,使用 let
代替 var
也是OK的:
function clickImageIcon(msgArr, options) { for (let i = 0; i < msgArr.length; i ++) { $('.file-wrapper:eq(' + i + ')').bind('click', function () { recognitionContent(msgArr[i]); $('#myModal').modal(options); }); } } |
至于为什么 let
代替 var
就能解决这个问题,我在 V2EX
上提了相应的问题,想要了解的请移步JavaScript let 关键字问题求解,总结来说就是 var
是函数级作用域,而 let
是块级作用域,所以 let
能起到和闭包相同的效果
另外 V2EX
上也有人提到 bind
函数的第二个参数就是子元素,所以下面的代码也可以:
function clickImageIcon(msgArr, options) { for (var i = 0; i < msgArr.length; i ++) { $('.file-wrapper:eq(' + i+ ')').bind('click', i, function (e) { recognitionContent(msgArr[e.data]); $('#myModal').modal(options); }); } } |
文章作者:KURANADO
发布时间:2018-03-20, 16:01:00
最后更新:2018-03-20, 16:03:41
原始链接:http://www.kuranado.com/2018/03/20/JavaScript匿名自执行函数以及闭包问题/