JavaScript: النطاق في JavaScript
آخر تحديث: 2026-10-13
النطاق يحدد أين يمكن الوصول إلى المتغير. فكّر فيه مثل بطاقة الهوية — هوية المدينة تعمل فقط داخل المحافظة، وهوية المحافظة لا تفيدك في الخارج. المتغيرات تعمل بنفس الطريقة: بمغادرتك نطاقها، تصبح غير قابلة للوصول.
1. أنواع النطاقات وقواعدها
المتغيرات المعلنة بـ var أو let أو const في المستوى الأعلى لها نطاق عام ويمكن الوصول إليها من أي مكان.
<script>
var globalVar = "أنا متغير عام";
function test() {
console.log(globalVar); // يمكن الوصول إليه
}
test();
</script>
المتغيرات العامة مريحة لكنها قد تلوث مساحة الأسماء — مع نمو المشروعات، تصبح تعارضات الأسماء حتمية. قلل من استخدام المتغيرات العامة.
(2) نطاق الدالة (Function Scope)
المتغيرات المعلنة بـ var تتبع نطاق الدالة: توجد فقط داخل الدالة الحالية وتختفي خارجها.
<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 تتبع نطاق الكتلة: توجد فقط داخل {} الحالية.
<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 من النطاق الحالي🦄، طبقة بطبقة، حتى يصل إلى النطاق العام. هذه السلسلة تسمى سلسلة النطاق.
<script>
const city = "بكين";
function outer() {
const district = "هايديان";
function inner() {
const street = "زونغوانغتشون";
console.log(street, district, city); // جميعها قابلة للوصول
}
inner();
}
outer();
</script>
النطاقات الخارجية لا يمكنها الوصول إلى متغيرات النطاقات الداخلية — مثل عدم قدرتك على الوصول إلى جيب طالب من خارج الفصل.
(5) الرفع (Hoisting)
إعلانات var "ترفع" إلى أعلى نطاقها، لكن التعيينات لا تُرفع:
<script>
console.log(a); // undefined (ليس خطأً!)
var a = 5;
// ترتيب التنفيذ الفعلي: var a; → console.log(a); → a = 5;
</script>
let و const تُرفع أيضاً، لكن الوصول إليها قبل الإعلان يسبب خطأً — هذه المنطقة تسمى المنطقة الزمنية الميتة (TDZ):
<script>
try {
console.log(b); // خطأ مرجعي!
} catch(e) {
console.log("المنطقة الزمنية الميتة: " + e.message);
}
let b = 5;
</script>
الخلاصة: استخدم دائماً let و const؛ تجنب مشكلات رفع var.
(6) الإغلاق (Closures) بشكل حدسي
الإغلاق = دالة + بيئة المتغيرات التي وُلدت فيها. مثل شخص غادر مسقط رأسه لكنه لا يزال يتذكر شكله — حتى لو تغير hometown لاحقاً، ذاكرته عنه تبقى كما هي.
<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 في الحلقات
▶ جرّب الكود▶ مثال: عرض سلسلة النطاق
▶ جرّب الكود▶ مثال: عداد الإغلاق مع متغيرات خاصة
▶ جرّب الكود▶ مثال: مقارنة الرفع
▶ جرّب الكود❓ أسئلة شائعة
var في حلقة for يسبب خروج جميع الاستدعاءات بالقيمة نفسها؟var لها نطاق الدالة — بعد انتهاء الحلقة، يوجد فقط i واحد، وجميع الاستدعاءات تشترك فيه (الذي يساوي القيمة النهائية للحلقة عند ذلك). مع let، كل تكرار يحصل على نسخة مستقلة من i.null.let أم const؟const كخيار افتراضي؛ استخدم let فقط عندما تحتاج إلى إعادة التعيين. هذه العادة تمنعك من تعديل المتغيرات التي لا ينبغي أن تتغير عن طريق الخطأ.📖 ملخص
- النطاق العام مرئي في كل مكان؛ نطاق الدالة محدود داخل الدالة؛ نطاق الكتلة محدود داخل
{} - سلسلة النطاقات تعني أن النطاقات الداخلية يمكنها الوصول إلى المتغيرات الخارجية، ولكن العكس لا يصح
varله نطاق دالة ورفع؛let/constلهما نطاق كتلة ومنطقة زمنية ميتة- الإغلاقات تسمح للدوال بـ"تذكر" نطاق إنشائها، مفيدة لإخفاء البيانات
- قلل المتغيرات العامة بتغليف الكود في دوال أو وحدات
📝 تمارين
- اكتب دالة
makeGreeter(greeting)تعيد دالة تستقبل اسماً وتعيدgreeting + "، " + name. أنشئ دالتي تحية بتحيتين مختلفتين وتحقق أنهما لا تتداخلان. - اكتب دالة
createWallet(initialBalance)تعيد ثلاث طرق:depositوwithdrawوgetBalance. يجب ألا يكونbalanceقابلاً للوصول مباشرة من الخارج (متغير خاص) — لا يمكن التلاعب به إلا من خلال هذه الطرق. - اشرح مخرجات الكود التالي وسببها:
<script>
for (var i = 0; i < 3; i++) {
setTimeout(function() { console.log(i); }, 100);
}
</script>
ثم عدّله ليطبع 0، 1، 2.