闭包的定义
MDN的解释:
- 一个函数和对其周围状态(lexical environment),词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure);
- 也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域;
- 在JavaScript中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。
执行函数:
函数执行中:
执行完函数adder,但是由于adder5还引用函数adder,所以函数adder不会被回收,又因为函数adder的作用域链关联着函数createAdder,所以函数createAdder也不会被回收,这就是闭包的作用。
内存释放
对于不再使用的闭包结构,我们需要及时释放内存。比如上述的案例,只需要将其赋值为null即可。
adder5 = null
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
</style>
</head>
<body>
<div>
<button id="btn1">创建数组</button>
<button id="btn2">销毁数组</button>
</div>
<script>
function createArray () {
var arr = new Array(1024*1024).fill(1);
return function () {
// arr 是上一层函数的变量,所以函数执行后不会销毁
console.log(arr);
}
}
var totalArr = [];
var createBtn = document.querySelector('#btn1');
var destroyBtn = document.querySelector('#btn2');
createBtn.onclick = function() {
for (let i = 0; i < 100; i++) {
totalArr.push(createArray());
}
}
destroyBtn.onclick = function() {
totalArr = null;
}
</script>
</html>
点击拍摄快照:
没创建数组之前的内存情况:
创建数组:
销毁数组:
我们可以看到,闭包使用完不及时清除,对内存的消耗还是挺大的。
浏览器对内存的优化
function createArray () {
let name = '张三';
let age = 18;
const sex = '男'
function test() {
debugger
console.log(name, sex);
}
return test;
}
var demo = createArray();
demo()
这个案例很明显是一个闭包的结构,但是我们发现浏览器并没有保存age这个变量。说明浏览器对此做了相关的优化,对于没有引用的变量进行清除。