المستوى: مبتدئ
لو لقيت دالة جوّانية في JavaScript بتقرأ متغير من دالة خارجية خلصت تنفيذها — مفروض المتغير ده اتمسح، لكنه شغّال. ده بالظبط الـ closure. المقال هيخليك تفهمه في 7 دقائق بمثال كود قصير، تعريف علمي دقيق، حالات الاستخدام، وحدود الأمان.
Closures في JavaScript: قاعدة واحدة بتفسّر كل اللخبطة
المشكلة باختصار
كل مبتدئ بيقابل الكود ده ويتلخبط:
function makeCounter() {
let count = 0;
return function () {
count++;
return count;
};
}
const counter = makeCounter();
counter(); // 1
counter(); // 2
counter(); // 3السؤال اللي بيتسأل في كل مقابلة عمل: ليه count لسه عايش؟ makeCounter خلصت ومفروض الـ scope بتاعها انمحى. لكن الرقم بيزيد كل مرة. السبب هو الـ closure.
المثال قبل التعريف العلمي
تخيّل درج صغير في مكتب فيه ورقة مكتوب عليها رقم. لما الموظف بيغادر المكتب، الدرج ما بيتحرقش. بيفضل في مكانه. لو الموظف ساب لزميله مفتاح الدرج قبل ما يمشي، الزميل يقدر يفتحه ويعدّل الرقم اللي جوّاه أي وقت. لو رمى المفتاح، الدرج بيتحرق فعلًا (الذاكرة بتترجع للنظام).
في الكود اللي فوق:
- الدرج = الـ scope بتاع
makeCounter. - الورقة جوّاه = المتغير
count. - المفتاح = الدالة المرجوعة (المخزّنة في
counter). - الموظف اللي مشي = استدعاء
makeCounterاللي خلص.
طول ما المفتاح موجود، الدرج ما يتحرقش. ده هو الـ closure حرفيًا.
التعريف العلمي الدقيق
الـ closure هو ربط بين دالة وبيئتها المعجمية (lexical environment) وقت إنشائها. كل دالة في JavaScript بتحفظ مرجع داخلي اسمه [[Environment]] بيشاور على الـ scope اللي اتعرّفت فيه. لما الدالة بتنفّذ، بتتعمل لها بيئة جديدة بتشاور على الـ [[Environment]] ده كأبوها.
طول ما الدالة لسه قابلة للوصول (reachable) من أي مكان في البرنامج، الـ Garbage Collector ما يقدرش يحرّر الـ scope اللي هي شايفاه. ده مش سحر، ده ECMAScript Spec — بالظبط القسم 9.2 (Function Environment Records).