الإغلاقات (Closures)
تعرف أصلًا النطاق (scope): من هنا أي الأسماء مرئية. خطوة أبعد: الدالة الداخلية قد تواصل استخدام اسم خارجي حتى بعد انتهاء استدعاء الدالة الخارجية. هذا الرابط المستمر يُسمّى إغلاقًا (closure).
ماذا يعني الإغلاق
يتشكّل الإغلاق عندما تُنشأ دالة داخل أخرى وتصل لاحقًا إلى ربطات الدالة الخارجية. قد يكون الاستدعاء الخارجي قد انتهى؛ والدالة الداخلية ما زالت «تتذكر» تلك الأسماء. لا تكتب كلمة closure في الكود — تكتب دوالًا متداخلة، وJavaScript يبقي الربطات الخارجية اللازمة حيّة.
ثلاث قطع راقبها
📊 الدالة الخارجية، الربط، والدالة الداخلية
| القطعة | الدور | إشارة للمبتدئ |
|---|---|---|
| الدالة الخارجية | تُنفَّذ مرة (أو أكثر) وغالبًا تُرجع دالة داخلية | استدعاء «الإعداد» |
| الربط الخارجي | معامل أو let / const في الخارجية |
القيمة التي ما زالت الداخلية تحتاجها |
| الدالة الداخلية | تستخدم ذلك الربط عند استدعائها لاحقًا | الدالة التي تبقيها |
إن استطعت الإشارة إلى هذه الثلاث، تشرح أغلب أمثلة الإغلاق للمبتدئين. المفاجأة ليست التداخل — بل أن الربط الخارجي يبقى مفيدًا بعد return الخارجي.
function makeLine(title) {
function show() {
console.log(title);
}
show();
}
makeLine("Shop");
أثناء الاستدعاء تنظر الداخلية للخارج
show لا تملك title محليًا. البحث يمشي للخارج إلى makeLine ويجد المعامل. هذا نطاق متداخل عادي. الإغلاق يخطو أبعد: أبقِ show (أو شبيهتها) لوقت لاحق بعد أن تعود makeLine.
function makeLine(title) {
return function show() {
console.log(title);
};
}
let printShop = makeLine("Shop");
printShop();
انتهى الاستدعاء الخارجي — والذاكرة بقيت
makeLine("Shop") تُرجع دالة. عندما تستدعي printShop لاحقًا ما زالت تطبع Shop. معامل title من ذلك الاستدعاء المنتهي ما زال قابلًا للوصول. هذا الالتقاط المستمر هو الإغلاق.
function makeGreeter(name) {
return function () {
return "Hello, " + name;
};
}
let hiSara = makeGreeter("Sara");
console.log(hiSara());
المصانع تُرجع دالة جاهزة
makeGreeter مصنع صغير: استدعاء خارجي واحد، دالة مخصّصة تعود. hiSara يحيّي سارا دائمًا لأنها أغلقت على ذلك name. غيّر وسيط makeGreeter تحصل على محيٍّ آخر — نفس النمط، ذاكرة جديدة.
function makeCounter() {
let n = 0;
return function () {
n = n + 1;
return n;
};
}
let tick = makeCounter();
console.log(tick());
console.log(tick());
حالة شبه خاصة بعدّاد
n يعيش في الدالة الخارجية. الكود الخارجي لا يلمس n مباشرة — فقط الدالة المُرجَعة تستطيع. الاستدعاء الأول يعيد 1 والثاني 2. العدّاد «يتذكر» بلا متغير عام.
function makeCounter() {
let n = 0;
return function () {
n = n + 1;
return n;
};
}
let a = makeCounter();
let b = makeCounter();
console.log(a());
console.log(a());
console.log(b());
كل استدعاء خارجي له ذاكرته
a وb جاءا من استدعاءَي makeCounter() منفصلين، فلكلٍ n خاص. ضربتان على a لا تجعل b يبدأ من المنتصف. الإغلاقات لا تتشارك حقيبة حالة تلقائيًا إلا إن شاركت عمدًا ربطًا خارجيًا واحدًا.
اعرض قيمة مُغلقة على الصفحة
ابنِ محيّيًا بالمصنع، استدعِه مرة، وضع السلسلة المُرجَعة في فقرة.
<!DOCTYPE html>
<html>
<head>
<title>closures — page</title>
</head>
<body>
<p id="msg">…</p>
<script>
function makeGreeter(name) {
return function () {
return "Hello, " + name;
};
}
let hi = makeGreeter("Omar");
let box = document.getElementById("msg");
box.textContent = hi();
</script>
</body>
</html>
الفقرة تعرض Hello, Omar. انتهى الاستدعاء الخارجي؛ وhi ما زال يعرف name. غيّر فقط السلسلة الممرَّرة إلى makeGreeter، حدّث، واقرأ السطر الجديد. الدرس التالي الكائنات (objects) — جمع قيم مرتبطة تحت اسم واحد.
تمارين
- اكتب دالة تُرجع دالة داخلية تطبع معاملًا خارجيًا.
- خزّن الدالة المُرجَعة في متغير واستدعِها بعد انتهاء الاستدعاء الخارجي.
- ابنِ
makeGreeter("Lina")واطبع السلسلة التي تُرجعها. - أنشئ عدّادًا واحدًا؛ استدعِه مرتين وتأكد أنك ترى
1ثم2. - أنشئ عدّادين؛ زد الأول مرتين فقط وتحقق أن الثاني يبدأ من
1. - في عرض HTML غيّر وسيط الاسم فقط، حدّث، واقرأ الفقرة.
أخطاء شائعة
- افتراض أن محليّات الخارجية تختفي فور
return— الداخلية قد تراها بعد ذلك - توقّع أن كل
makeCounter()يشاركnواحدًا — عادة لكل استدعاء ذاكرة خاصة - ظن أن «الإغلاق» يعني فقط كلمة
return— قد يُرجع الدالة الداخلية، لكن الذاكرة هي الربط المُغلق - وضع كل قيمة يُراد تذكرها على الكائن العام «للتبسيط»
- توقّع درس الكائنات كاملًا هنا — تجميع الخصائص تحت قيمة واحدة في الصفحة التالية
خلاصة
- الإغلاق يتيح لدالة داخلية استخدام أسماء خارجية بعد انتهاء الاستدعاء الخارجي
- تكتب دوالًا متداخلة؛ وJavaScript يبقي الربطات اللازمة حيّة
- المصانع تُرجع دالة مخصّصة تتذكر قيم الإعداد
- العدّاد يخفي
nخاصًا خلف الدالة المُرجَعة - الاستدعاءات الخارجية المنفصلة تعني عادة ذاكرات منفصلة
- تحديث الصفحة قد يعرض سلسلة أنتجتها قيمة مُغلقة
- التالي: الكائنات — قيم مرتبطة تحت اسم واحد
🧠 اختبر معرفتك
اختبر معرفتك
تحدى نفسك مع هذا الاختبار التفاعلي واكتشف مدى فهمك للموضوع
📝 التعليمات
- اقرأ كل سؤال بعناية
- اختر أفضل إجابة لكل سؤال
- يمكنك إعادة الاختبار عدة مرات كما تريد
- سيتم عرض تقدمك في الأعلى