这里的闭包我不是很理解
它是如何产生的?
以及为什么可以用更多的闭包来解决它?
说一下我的理解
先说产生,代码的满足闭包产生的条件
1.方法中存在函数的嵌套,也就是setupHelp嵌套了匿名函数
2.内层函数使用外层函数的变量,也就是item(这边由于使用的是var所以item被上升到了setupHelp的环境)
3.外层函数返回内层函数的引用。最终匿名函数被赋给了onfocus,达到了这个效果
可以这样的解决的原因是通过函数工厂
,让所有的回调不再共享同一个词法环境。
修改后的方法中的环境是变为了makeHelpCallback
内部
for (var i = 0; i < helpText.length; i++) {
// 这个 item 被提升到 setupHelp 了,导致循环每执行一次,
// item 就要被重新赋值一次
var item = helpText[i];
document.getElementById(item.id).onfocus = function() {
// 由于 item 被重新赋值了,这里被执行的时候,访问到的是 item
// 的最后一个值 helpText[helpText.length - 1]
// 而不是所期望的 helpText[i]
showHelp(item.help);
}
}
至于所谓闭包,其实就是引擎发现你有个尚未执行的函数里引用了外头的 item
,于是很贴心地帮你把这个 item
所在的“区域”也保存下来了,你这个尚未执行的函数和被保留的“区域”合起来,就成了一个“闭包”。
闭包可以理解为:一个函数及其周围封闭词法环境中的引用构成闭包。可能这句话还是不好理解,
示例:
function createAction() {
var message = "封闭环境内的变量";
return function() {
console.log(message);
}
}
const showMessage = createAction();
showMessage(); // output: 封闭环境内的变量
更加详细的可以看这个大佬写的文章:还搞不懂闭包算我输(JS 示例)
8 回答4.7k 阅读✓ 已解决
6 回答3.4k 阅读✓ 已解决
5 回答2.8k 阅读✓ 已解决
5 回答6.3k 阅读✓ 已解决
4 回答2.3k 阅读✓ 已解决
4 回答2.8k 阅读✓ 已解决
3 回答2.4k 阅读✓ 已解决
MDN 关于闭包的解释:
前半句有些许拗口,我的理解就是
一个函数 + 使用到自由变量
,自由变量
指的是既不是这个函数的参数也不是这个函数的局部变量的变量。所以后半句说只要创建一个函数,闭包就会被创建。即从技术角度说,所有的函数都是闭包。
因此例子中
onfocus
的事件处理函数是一个闭包。原示例没有达到预期效果的原因是因为
var
声明的item
变量不存在块作用域,会变量提升
,相当于在setupHelp
函数的顶层定义了一样,所以当循环结束后,item
指向的是最后一项。所以要解决这个问题,最快的就是改用let
声明。至于更多闭包
,其实就是让每个事件处理函数访问到当前下标的item
,即每次循环都创建额外一个函数去提供自由变量
。