انتقل إلى محتوى الدرس
الدرس 49
دورة جافا سكريبت

المغلفات البرمجية Closures في JavaScriptJavaScript Function Closures

أتقن المغلفات البرمجية Closures والبيئة المعجمية في JavaScript للاحتفاظ بالحالة الخاصة وبناء العدادات المحمية ومعالجة فخ الحلقات التكرارية عبر let.
أقسام الدرس
5
الأمثلة
2
اللغة
العربية
تاريخ النشر
غير محدد
المشاهدات
4,233
محتوى الدرس
في هذا الدرس 5تصفّح المواضيع

تعتمد JavaScript نظام النطاق المعجمي الثابت (Lexical Scoping)؛ أي أن قدرة الدالة على رؤية المتغيرات المحيطة تتحدد وفق المكان الذي كُتبت فيه داخل الكود المصدري لا مكان استدعائها. فكل دالة داخلية متداخلة ترى تلقائياً معاملات ومتغيرات دالتها الأم المحيطة بها.

مخطط آلية عمل المغلف Closure من الدالة المصنعية وإرجاع الدالة الداخلية مع حقيبة متغيراتها الخاصة المحمية

تأمل معضلة العداد الشهيرة: إذا وضعت let count = 0 في النطاق العام، استطاع أي سطر بالصفحة تخريبه وإسناد قيمة خاطئة له. وإن وضعته داخل دالة عادية، تصفّر وعاد إلى 0 في كل استدعاء! وهنا تحل المغلفات (Closures) المشكلتين معاً بكفاءة باهرة:

طريقة تخزين الحالةهل تحتفظ بالقيمة بين الاستدعاءات؟هل هي محمية من العبث الخارجي؟
متغير عام بالملفنعم، يبقى طوال فتح الصفحةلا، أي كود خارجي يمكنه تغييره بالخطأ
متغير محلي عاديلا، يُنشأ من الصفر عند كل استدعاءنعم، معزول داخل الدالة
متغير داخل Closureنعم، محفوظ في البيئة المعجمية المرافقةنعم، لا يُقرأ ولا يُعدل إلا عبر الدالة المرجعة

يُعرّف المغلف البرمجي (Closure) بأنه اقتران الدالة برابط حي نحو بيئتها المعجمية المحيطة. فعندما تُرجع الدالة الخارجية دالةً داخلية وتنتهي مهمتها على مكدس الاستدعاءات، لا تُمسح متغيراتها المحلية بل تبقى حية في «حقيبة ذاكرة» خفية ترافق الدالة المرجعة أينما ذهبت!

JavaScript
function makeBadge(prefix) {
  return function (memberName) {
    return '[' + prefix + '] ' + memberName;
  };
}
const vipTag = makeBadge('VIP');
document.getElementById('cls-out').textContent = vipTag('Faisal');

ينشئ كل استدعاء لدالة مصنعية مثل createCounter() بيئة مغلف مستقلة تماماً في الذاكرة؛ فاستدعاء counterA() يزيد عداده الخاص دون أي تأثير على counterB()، ولا يملك أي كود خارجي وسيلة للوصول المباشر إلى المتغير count أو تخريبه.

JavaScript
function createCounter(start) {
  let count = start;
  return function () {
    count += 1;
    return count;
  };
}
const nextTicket = createCounter(100);
document.getElementById('cnt-cls').textContent = nextTicket() + ' -> ' + nextTicket();

عند إنشاء دوال داخل حلقة تستخدم var i، ينشئ المحرك متغيراً واحداً مشتركاً لكل الدورات؛ وحين تعمل تلك الدوال لاحقاً تجد أن i قد وصلت إلى القيمة النهائية بعد انتهاء الحلقة! أما استبدالها بـ let i فينشئ نسخة مستقلة في كل دورة تحتفظ بها كل دالة داخل مغلفها بدقة.

خلاصة المعرفة ومحطة الانتقال

ملخص الدرس

حصاد الدرس

مراجعة مركّزة لأهم المفاهيم والقواعد الهندسية التي أتقنتها في هذا الدرس قبل التطبيق العملي

ماذا تعلّمت في هذا الدرس؟

أتقنت في هذا الدرس البيئة المعجمية، وآلية احتفاظ المغلفات Closures بذاكرة الدالة الأم، وبناء العدادات الخاصة المحمية، وحل فخ الحلقات الشهير عبر let. الخطوة التالية: انتقل إلى درس «نطاق المتغيرات والرفع في JavaScript» لرسم الخريطة الشاملة لسلسلة النطاقات وآلية الرفع Hoisting.

مشاركة

هل كان هذا الدرس مفيدًا؟

جارٍ تحميل الآراء…

ابنِ لغتك البرمجية

المصطلحات3

راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.

0 / 3 مفهومةأول بطاقة، أول خطوة
01 Closure المغلف البرمجي Closure
اقتران الدالة الداخلية برابط حي نحو متغيرات بيئتها المعجمية المحيطة حتى بعد انتهاء تنفيذ الدالة الخارجية.
للمراجعة
02 Lexical Scoping النطاق المعجمي الثابت
قاعدة تحديد رؤية المتغيرات تبعاً لموضع كتابة الدالة وتداخلها النصي في الكود المصدري.
للمراجعة
03 Factory Function الدالة المصنعية
دالة تهيئ متغيرات محلية خاصة ثم ترجع دالة أو كائناً يمتلك صلاحية حصرية للتعامل مع تلك المتغيرات.
للمراجعة

اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.

حروف قليلة. معنى كامل.

الاختصارات2

راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.

0 / 2 مفهومةأول بطاقة، أول خطوة
01 VIP VIP
Very Important Person Tier
فئة العضوية المحفوظة داخل البيئة المعجمية لدالة التوسيم في مثال المصنع.
للمراجعة
02 RAM RAM
Random Access Memory
ذاكرة النظام الحية التي يحتفظ فيها المحرك بمتغيرات المغلف طالما بقيت الدالة الداخلية قابلة للاستدعاء.
للمراجعة

اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.

من الفهم للتطبيق

مهامك قبل الاختبار

خطوة صغيرة كل مرة. وإنجاز تقدر ترجع له.

0/2مهام منجزة
  1. بدّل بين التبويبين الثاني والثالث في محاكي المغلفات لمشاهدة سبب إنتاج var للرقم 4 واحتفاظ let بقيم الدورات.

  2. افتح مثال createCounter وأنشئ عداداً ثانياً يبدأ من 500 للتحقق من استقلال ذاكرة كل مغلف.

تأشير المهمة إقرار منك بإتمامها، وليس تصحيحًا آليًا للكود. يُحفظ تقدمك في حسابك.

مساحة التحدي

اختبر فهمك.
ووصلها للإتقان.

كل سؤال خطوة لقدّام. اختار، اكتب كود، وشوف نتيجتك فورًا.

10أسئلة 2أنواع تحديات 100%هدف الإتقان
تصحيح تلقائي. فرص بلا حدود.

أكمل المهام، واجمع كل الإجابات الصحيحة. أقل من 100%؟ راجع وأعد المحاولة.

الأسئلة متاحة للاطلاع. سجّل الدخول للتفاعل وحفظ تقدمك.

لمحة عن التحدي10 أسئلة تنتظرك
01

ما التعريف الدقيق للمغلف البرمجي (Closure) في لغة JavaScript؟

02

عندما ترجع الدالة الخارجية دالة داخلية، تبقى المتغيرات المحلية المستخدمة في الدالة الداخلية محفوظة في الذاكرة.

03

إذا أنشأنا عدادين مستقلين عبر createCounter(0) وشغلنا الأول ثلاث مرات، فماذا يحدث للعداد الثاني؟

04

لماذا ترجع جميع الدوال المنشأة داخل حلقة "for (var i = 1; i <= 3; i++)" الرقم 4 عند تشغيلها بعد الحلقة؟

05

ما التعديل المباشر بكلمة واحدة الذي يعالج فخ المغلفات داخل حلقة for لتتذكر كل دالة رقم دورتها؟

06

يحدد النطاق المعجمي وصول الدالة للمتغيرات وفق موضع كتابتها في الكود لا مكان استدعائها.

07

تجمد المغلفات المتغيرات الخارجية نهائياً فلا تستطيع الدالة الداخلية تحديثها أو زيادة قيمتها.

08

لماذا يُعد العداد المبني عبر Closure أكثر أماناً من وضع متغير عداد في النطاق العام؟

09

حفظ مفاتيح الخادم السرية داخل Closure في ملف الواجهة الأمامية يخفيها تماماً عن أدوات مطوري المتصفح.

10

كيف يمكن لمغلف واحد إتاحة دالتين مثل increment وgetCount تعملان معاً على نفس المتغير الخاص؟