面试题答案
一键面试闭包对内存管理的影响
- 延长变量生命周期:闭包会使函数内部的变量在函数执行完毕后依然存在于内存中,因为闭包持有对这些变量的引用。例如:
function outer() {
let localVar = 10;
function inner() {
return localVar;
}
return inner;
}
let closureFunc = outer();
console.log(closureFunc());
在上述代码中,outer
函数执行完毕后,localVar
变量本应被销毁,但由于 inner
函数形成的闭包持有对 localVar
的引用,所以 localVar
仍然保留在内存中。
- 增加内存占用:如果闭包大量使用且长时间不释放,会导致内存占用不断增加,可能影响系统性能。
可能因闭包导致的内存泄漏场景
- 循环引用导致内存泄漏:
function createLeak() {
let element = document.createElement('div');
element.onclick = function() {
console.log(element.id);
};
return element;
}
let leakElement = createLeak();
document.body.appendChild(leakElement);
在这个例子中,element
元素的 onclick
事件处理函数形成了闭包,闭包又持有对 element
的引用,即使 createLeak
函数执行完毕,element
因为闭包的引用而无法被垃圾回收机制回收,从而导致内存泄漏。
- 定时器中的闭包导致内存泄漏:
function setupInterval() {
let data = { value: 1 };
setInterval(() => {
console.log(data.value);
}, 1000);
return data;
}
let intervalData = setupInterval();
这里 setInterval
的回调函数形成闭包,持有对 data
的引用,使得 data
无法被垃圾回收,可能导致内存泄漏。
避免闭包导致内存泄漏的方法
- 手动解除引用:对于上述
element
的例子,可以在适当的时候手动解除onclick
事件处理函数的引用:
function createLeak() {
let element = document.createElement('div');
let clickHandler = function() {
console.log(element.id);
};
element.onclick = clickHandler;
// 假设在某个时候不再需要这个事件处理函数
element.onclick = null;
return element;
}
let leakElement = createLeak();
document.body.appendChild(leakElement);
- 合理管理定时器:在不需要定时器时,使用
clearInterval
清除定时器,以解除闭包对相关变量的引用:
function setupInterval() {
let data = { value: 1 };
let intervalId = setInterval(() => {
console.log(data.value);
}, 1000);
// 假设在某个时候不再需要定时器
clearInterval(intervalId);
return data;
}
let intervalData = setupInterval();