JavaScript: النطاق في JavaScript

آخر تحديث: 2026-10-13

النطاق يحدد أين يمكن الوصول إلى المتغير. فكّر فيه مثل بطاقة الهوية — هوية المدينة تعمل فقط داخل المحافظة، وهوية المحافظة لا تفيدك في الخارج. المتغيرات تعمل بنفس الطريقة: بمغادرتك نطاقها، تصبح غير قابلة للوصول.

تصريحات ذات صلة:const let var for

1. أنواع النطاقات وقواعدها

المتغيرات المعلنة بـ var أو let أو const في المستوى الأعلى لها نطاق عام ويمكن الوصول إليها من أي مكان.

HTML
<script>
var globalVar = "أنا متغير عام";
function test() {
  console.log(globalVar); // يمكن الوصول إليه
}
test();
</script>

المتغيرات العامة مريحة لكنها قد تلوث مساحة الأسماء — مع نمو المشروعات، تصبح تعارضات الأسماء حتمية. قلل من استخدام المتغيرات العامة.

(2) نطاق الدالة (Function Scope)

المتغيرات المعلنة بـ var تتبع نطاق الدالة: توجد فقط داخل الدالة الحالية وتختفي خارجها.

HTML
<script>
function greet() {
  var message = "مرحباً";
  console.log(message); // يعمل بشكل صحيح
}
greet();
try {
  console.log(message); // خطأ مرجعي!
} catch(e) {
  console.log("فشل الوصول: " + e.message);
}
</script>

مشكلة شائعة مع نطاق دالة var: استخدام var في حلقة for يعني أن المتغير "يتسرب" بعد انتهاء الحلقة.

(3) نطاق الكتلة (Block Scope)

المتغيرات المعلنة بـ let و const تتبع نطاق الكتلة: توجد فقط داخل {} الحالية.

HTML
<script>
if (true) {
  let x = 10;
  const y = 20;
  var z = 30;
  console.log("داخل الكتلة: x=" + x + "، y=" + y + "، z=" + z);
}
console.log("خارج الكتلة: z=" + z); // var غير مقيد بالكتلة
try {
  console.log(x); // x غير قابل للوصول هنا
} catch(e) {
  console.log("x غير قابل للوصول: " + e.message);
}
</script>

لهذا يجب استخدام let بدلاً من var في عدادات الحلقات.

(4) سلسلة النطاق (Scope Chain)

النطاقات الداخلية يمكنها الوصول إلى متغيرات النطاقات الخارجية — مثل استخدامك لأشياء من المنزل في المدرسة (إذا أحضرتها). عند البحث عن متغير، يبحث JavaScript من النطاق الحالي🦄، طبقة بطبقة، حتى يصل إلى النطاق العام. هذه السلسلة تسمى سلسلة النطاق.

HTML
<script>
const city = "بكين";
function outer() {
  const district = "هايديان";
  function inner() {
    const street = "زونغوانغتشون";
    console.log(street, district, city); // جميعها قابلة للوصول
  }
  inner();
}
outer();
</script>

النطاقات الخارجية لا يمكنها الوصول إلى متغيرات النطاقات الداخلية — مثل عدم قدرتك على الوصول إلى جيب طالب من خارج الفصل.

(5) الرفع (Hoisting)

إعلانات var "ترفع" إلى أعلى نطاقها، لكن التعيينات لا تُرفع:

HTML
<script>
console.log(a); // undefined (ليس خطأً!)
var a = 5;
// ترتيب التنفيذ الفعلي: var a; → console.log(a); → a = 5;
</script>

let و const تُرفع أيضاً، لكن الوصول إليها قبل الإعلان يسبب خطأً — هذه المنطقة تسمى المنطقة الزمنية الميتة (TDZ):

HTML
<script>
try {
  console.log(b); // خطأ مرجعي!
} catch(e) {
  console.log("المنطقة الزمنية الميتة: " + e.message);
}
let b = 5;
</script>

الخلاصة: استخدم دائماً let و const؛ تجنب مشكلات رفع var.

(6) الإغلاق (Closures) بشكل حدسي

الإغلاق = دالة + بيئة المتغيرات التي وُلدت فيها. مثل شخص غادر مسقط رأسه لكنه لا يزال يتذكر شكله — حتى لو تغير hometown لاحقاً، ذاكرته عنه تبقى كما هي.

HTML
<script>
function createCounter() {
  let count = 0;        // هذا المتغير "مقفل" داخل الإغلاق
  return function() {
    count++;
    return count;
  };
}

const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3
// متغير count لم يُدمر لأن الدالة المرجعة لا تزال "تتذكره"
</script>

createCounter انتهت من التنفيذ منطقياً — كان يجب أن يُدمر count. لكن الدالة المرجعة تحتفظ بـ count بإحكام، فيبقى حياً. هذا هو الإغلاق.

(7) حالات استخدام عملية للإغلاق


▶ مثال: فرق var وlet في الحلقات

▶ جرّب الكود

▶ مثال: عرض سلسلة النطاق

▶ جرّب الكود

▶ مثال: عداد الإغلاق مع متغيرات خاصة

▶ جرّب الكود

▶ مثال: مقارنة الرفع

▶ جرّب الكود

تصريحات ذات صلة:const let var for

❓ أسئلة شائعة

س لماذا استخدام var في حلقة for يسبب خروج جميع الاستدعاءات بالقيمة نفسها؟
ج لأن var لها نطاق الدالة — بعد انتهاء الحلقة، يوجد فقط i واحد، وجميع الاستدعاءات تشترك فيه (الذي يساوي القيمة النهائية للحلقة عند ذلك). مع let، كل تكرار يحصل على نسخة مستقلة من i.
س هل الإغلاقات تسبب تسرب الذاكرة؟
ج الإغلاقات نفسها ليست تسرب ذاكرة — إنها تحفظ مراجع للمتغيرات عمداً. التسرب الحقيقي يحدث عندما لا تحتاج إغلاقاً لكنه لا يزال محتفظاً بسلسلة مرجعية أخرى، مما يمنع المتغير من أن يُجمع كقمامة. الحل: اجعل المرجع يساوي null.
س هل أستخدم let أم const؟
ج استخدم const كخيار افتراضي؛ استخدم let فقط عندما تحتاج إلى إعادة التعيين. هذه العادة تمنعك من تعديل المتغيرات التي لا ينبغي أن تتغير عن طريق الخطأ.

📖 ملخص

📝 تمارين

  1. اكتب دالة makeGreeter(greeting) تعيد دالة تستقبل اسماً وتعيد greeting + "، " + name. أنشئ دالتي تحية بتحيتين مختلفتين وتحقق أنهما لا تتداخلان.
  2. اكتب دالة createWallet(initialBalance) تعيد ثلاث طرق: deposit و withdraw و getBalance. يجب ألا يكون balance قابلاً للوصول مباشرة من الخارج (متغير خاص) — لا يمكن التلاعب به إلا من خلال هذه الطرق.
  3. اشرح مخرجات الكود التالي وسببها:
HTML
<script>
for (var i = 0; i < 3; i++) {
  setTimeout(function() { console.log(i); }, 100);
}
</script>

ثم عدّله ليطبع 0، 1، 2.

Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%