不断更新:整理常见的闭包问题
不断积累和整理在JavaScript中常见的闭包问题,不断加深理解和学习运用:
参考MDN网址:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures
闭包的官方定义: 闭包是由函数以及创建该函数的词法环境组合而成。这个环境包含了这个闭包创建时所能访问的所有局部变量(摘自MDN)
闭包的简单理解:希望在另一个作用域(比如在global中)访问局部作用域中的某个变量或函数
(在谷歌浏览器中调试,发生闭包会有closure字样提示)
问题一:闭包的“雏形”:在全局作用域中访问某局部作用域中的变量或函数:
function fn() { var name = 'zs'; return function () { return name; } } var f = fn(); var n = f(); //或者这样写: var n= fn()(); console.log(n) //zs
问题二:用闭包解决在for循环中绑定事件的问题
假设不使用闭包解决这个问题,点击绑定的li的值输出的都是最后的一个值,因为触发点击事件的时候for循环已经结束了,且在for循环的作用域中 i 的值不断被覆盖
var list = document.getElementByTagName('li'); for (var i = 0 ;i < list.length ;i++){ var li = list[i]; ( function (index){ li.onclick = function(){ alert( index ); } })(i) }
自执行函数从全局作用域中访问for循环里面的 i, 给每个 i 都新开创了一个作用域,让它保存i的值
但过多的开创独立作用域,会造成额外的开销消耗性能,所以闭包有利有弊,像上面这种问题可以使用let来解决
延伸:其他解决改问题的方法(使用let定义i)
var list = document.getElementByTagName('li'); for (let i = 0 ;i < list.length ;i++){ li.onclick = function(){ alert( i ); } }
问题三:用闭包解决在for循环中 setTimeout() 的问题
console.log(111) for ( var i = 0 ; i<3 ; i++){ setTimeout(function () { console.log(i) }, 0 ) } console.log(222) 最后的执行结果: 111 222 3 3 3
当js执行到setTimeout时会将其自动放入异步队列中去等待,直到主代码执行完后再去执行异步队列中的代码,于是3个3会在最后出现
使用闭包的方法避免这种情况:
console.log(111) for ( var i = 0 ; i<3 ; i++){ (function (index){ setTimeout(function () { console.log(i) }, 0 ) })(i) } console.log(222)
输出结果:
111
222
0
1
2
问题四:从闭包的角度给button等元素绑定事件demo
<a href="#" id="size-12">12</a> <a href="#" id="size-14">14</a> <a href="#" id="size-16">16</a>
function makeSizer(size) { return function() { document.body.style.fontSize = size + 'px'; }; } var size12 = makeSizer(12); var size14 = makeSizer(14); var size16 = makeSizer(16);
document.getElementById('size-12').onclick = size12; document.getElementById('size-14').onclick = size14; document.getElementById('size-16').onclick = size16;
size12
,size14
和 size16
三个函数将分别把 body
文本调整为 12,14,16 像素。我们可以将它们分别添加到按钮的点击事件上。
总结:
上面是闭包的几个典型例子,除此之外闭包常见的问题还有用闭包模拟私有方法等等,同时要注意开创闭包后要给它赋值为null来清除,避免其常驻内存,造成内存泄漏等问题影响性能,当然还有其他方式。
闭包考量性能,既实用,同时也有弊端。
运用好闭包是掌握JS的重点之一。革命尚未成功,同志仍需努力!