在一个函数的环境中,闭包 = 函数 + 词法环境
function m() {
var a = 1;
function sub() {}
}
垃圾是不再需要的东西,但是 JS 无法知道你哪些需要哪些不需要,因此 JS 会将无法触达的东西定义为垃圾(相当于 JS 回收的垃圾是所有垃圾的一个子集)
let nums = [1, 2, 3, 4, 5]
nums = [6, 7, 8, 9, 10]
const sum = nums.reduce((total, num) => total + num)
console.log(sum)
此时第一个数组就会被 JS 判定为垃圾(你没有任何机会访问到它了,无法触达),直接回收
let nums = [1, 2, 3, 4, 5]
const sum = nums.reduce((total, num) => total + num)
console.log(sum)
此时,JS 不知道你以后还会不会用 nums,所以不会回收
如果你以后都不用 nums 了(被你定性为垃圾),那么就会造成内存泄漏
仍可触达,但不再需要了
此时可以手动将该数组改为无法触达
let nums = [1, 2, 3, 4, 5]
const sum = nums.reduce((total, num) => total + num)
console.log(sum)
nums = null
结合闭包:
function createIncrease() {
const doms = new Array(100000).fill(0).map((_, i) => {
const dom = document.createElement('div')
dom.innerHTML = i
return dom
})
function increase() {
doms.forEach((dom) => {
dom.innerHTML = Number(dom.innerHTML) + 1
})
}
return increase
}
const increase = createIncrease();
const btn = document.querySelector('button')
function handleClick() {
increase()
btn.removeEventListener('click', handleClick)
increase = null
}
btn.addEventListener('click', handleClick)
此时如果掉以轻心,不把 increase = null
,就会因为闭包环境关联的 doms 造成内存泄漏
总结一下,闭包什么情况下会造成内存泄漏?
- 持有了不再需要的函数引用,导致函数关联的词法环境无法销毁
当多个函数共享词法环境时,会导致词法环境膨胀,从而导致出现无法触达也无法回收的内存
function createIncrease() { const doms = new Array(100000).fill(0).map((_, i) => { const dom = document.createElement('div') dom.innerHTML = i return dom }) function increase() {} function _temp() { doms } return increase } const increase = createIncrease(); const btn = document.querySelector('button') btn.addEventListener('click', () => { increase = createIncrease() })
此时 doms 是一块无法触达的内存空间,但又无法回收
因为
increase
和_temp
的词法环境一样,_temp
要用到 doms,所以垃圾回收器不会销毁