Closure และ Memory Leak
Closure: Inner Function ที่เข้าถึง Variable ของ Outer Function ได้ แม้ Outer Return แล้ว
ตัวอย่างปัญหา
<script>
window.onload = function parentFunction(arg1) {
var a = arg1; // Captured by Closure
return function childFunction(arg2) {
alert(a + ' ' + arg2); // ใช้ a
};
};
var val = parentFunction('outer val');
val('inner val'); // Alert: 'outer val inner val'
// 'a' ค้างใน Memory ตลอดที่ val ยังอยู่
</script>
Memory Leak Pattern: Accumulating Closures
var cache = {};
function getData(key) {
if (!cache[key]) {
// Heavy Computation
const largeData = new Array(1000000).fill('x');
cache[key] = function() { return largeData; }; // Closure captures largeData!
}
return cache[key]();
}
// cache ไม่เคย Clear → Memory Leak
วิธีป้องกัน
1. Nullify References
function parentFunction(arg1) {
var a = arg1;
const handler = function childFunction(arg2) {
alert(a + ' ' + arg2);
};
// ตัด Reference เมื่อไม่ใช้
return {
handler,
destroy() { a = null; } // Manual Cleanup
};
}
2. ใช้ IIFE แยก Scope (ตัวอย่างต้นฉบับ)
window.onload = function parentFunction() {
var obj1 = function childFunction1() {
document.write('the leak is avoided');
};
(function childFunction2() {
var obj2 = document.getElementById('closure');
obj2.onclick = obj1; // obj1 ไม่ Capture parent Scope
})();
};
3. WeakMap สำหรับ Cache
const cache = new WeakMap();
function getData(obj) {
if (!cache.has(obj)) {
cache.set(obj, heavyComputation(obj));
}
return cache.get(obj);
}
// Obj ถูก GC → Cache Entry หาย Auto
4. Event Listener Cleanup
element.addEventListener('click', handler);
// ตอน Destroy:
element.removeEventListener('click', handler);