闭包的定义:
函数和对其周围状态的引用捆绑在一起构成闭包(MDN文档中的闭包定义)
函数和函数内部能访问到的变量(也叫环境)的总和,就是一个闭包。(某大佬对于闭包的定义)
闭包的特点:
(1)让外部访问函数内部变量成为可能;
(2)局部变量会常驻在内存中;
(3)可以避免使用全局变量,防止全局变量污染;
(4)闭包就是可以创建一个独立的环境,互不干扰。
相关代码帮助理解:
//最常见的闭包类型,函数嵌套,子函数引用父函数的变量,形成闭包
function init() {
var name = 'js; // name 是一个被 init 创建的局部变量
return function GN() { // GN为内部函数,与引用的变量name形成一个闭包
console.log(name); // 使用了父函数中声明的变量
}
}
var func = init();
func(); //js
/*使变量name的值始终保持在内存中,不会在init调用后被自动清除。
为什么会这样呢?原因就在于init是GN的父函数,而GN被赋给了一个全局变量,这导致GN始终在内存中,而GN的存在依赖于init,因此init也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。
闭包的应用:
1.let关键字出现前用闭包模拟块级作用域
//高频笔试面试题
for (var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i);
}, 0);
} //5,5,5,5,5; var没有块级作用域,共享同一个i
for (let i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i);
}, 0);
} //0,1,2,3,4
for (var i = 0; i < 5; i++) {
setTimeout((function() {
console.log(i);
})(i), 0);
} //0,1,2,3,4; 函数自执行写法形成闭包,模拟块级作用域
2.避免变量污染(创建私有变量)
假设我们在做一个游戏,在写其中关于「还剩几条命」的代码。
如果不用闭包,你可以直接用一个全局变量:
window.lives = 30 // 还有三十条命
这样看起来很不妥,万一不小心把这个值改直接成 -1 了怎么办。所以我们不能让别人直接访问这个变量。但是用局部变量别人又访问不到,怎么办呢?
暴露一个访问器(函数),让别人可以间接访问。
代码如下:
function(){
var lives = 50 //私有变量
window.addl = function(){
lives += 1
}
window.reducel = function(){
lives -= 1
}
}
那么在其他的 JS 文件中,就可以使用 window.addl() 来涨命,使用 window.reducel() 来让角色掉一条命。
关于闭包的误解
闭包会造成内存泄露?错。
内存泄漏是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果
这个谣言是如何来的?
是因为 IE浏览器(IE6)垃圾回收机制有问题。导致我们使用完闭包之后,依然回收不了闭包里面引用的变量。所以是 IE浏览器 的bug,不是闭包的问题。
使用闭包的注意点:
由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。
参考文章:「每日一题」JS 中的闭包是什么?