أحمد حايس
الرئيسيةمن أناالدوراتالمدونةالعروض
أحمد حايس

دورات عربية متخصصة في التقنية والبرمجة والذكاء الاصطناعي.

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

تعلم أسرعوصول مباشر للدورات والمسارات من الموبايل.
تنقل أوضحالروابط الأساسية والدعم في مكان واحد بدون تشتيت.

المنصة

  • الرئيسية
  • من أنا
  • الدورات
  • العروض
  • المدونة

الدعم

  • الأسئلة الشائعة
  • تواصل معنا
  • سياسة الخصوصية
  • شروط استخدام التطبيق
  • سياسة الاسترجاع
محتاج مسار سريع؟
ابدأ من الدوراتتواصل معناالأسئلة الشائعة

© 2026 أحمد حايس. جميع الحقوق محفوظة.

الرئيسيةالدوراتالعروضالمدونةالدخول
البرمجة بالعربي

Hoisting في JavaScript للمبتدئ: ليه var شغّال قبل تعريفه و let بيرمي خطأ

📅 ٨ مايو ٢٠٢٦⏱ 5 دقائق قراءة
Hoisting في JavaScript للمبتدئ: ليه var شغّال قبل تعريفه و let بيرمي خطأ

المستوى: مبتدئ

Hoisting في JavaScript: ليه var x شغّال قبل تعريفه و let x بيرمي خطأ

لو كتبت console.log(x); var x = 5; الكود بيشتغل ويطبع undefined بدون أي خطأ. لو غيّرت var لـ let، الكود بيقع بـ ReferenceError. الفرق ده اسمه Hoisting، وفهمه بيوفّر عليك ساعات بحث في bugs مش منطقية على إطلاق.

مصعد زجاجي حديث في برج مكاتب يرفع المستخدمين لأعلى — تشبيه بصري لرفع تعريفات المتغيرات في JavaScript Hoisting

المشكلة باختصار

كتير من المبتدئين بيشوفوا رسالة ReferenceError: Cannot access 'x' before initialization ومش فاهمين السبب — خصوصًا إن نفس الكود بـ var كان شغّال طبيعي قبل ما يحوّلوا الكود لـ let. السبب إن JavaScript بيمر على الكود بتاعك مرّتين، والمرور الأول بيرفع تعريفات المتغيرات لأعلى الـ scope. هنا هتفهم بالظبط ايه اللي بيحصل، ولاحظ الفرق بين var و let و const والـ functions.

تخيّل الموقف بمثال بسيط

تخيّل إنك بتسافر بكرة الصبح. الليلة اللي قبل، بتفتح الحقيبة وتكتب على ورقة كل اللي محتاجه: «جواز السفر، التذكرة، الشاحن، الـ headphones». لسه ما حطّيتش الحاجات نفسها جوا الحقيبة — بس الأسماء معروفة عندك. لما الصبح يجي، بتمشي على الورقة وتحط كل حاجة في مكانها.

JavaScript بيعمل نفس الفكرة بالظبط. أول ما بيشوف الكود بتاعك، بيمر مرور سريع يكتب «قائمة الحاجات» — يعني يلاقي كل تعريفات var و function ويحجزلها مكان في الذاكرة. بعد كده بييجي يشغّل الكود سطر سطر من فوق لتحت. ده اسمه Hoisting: «رفع» التعريفات لأعلى الـ scope في مرحلة الإنشاء قبل التنفيذ.

التعريف العلمي بالظبط

طبقًا لـ ECMAScript Language Specification (ECMA-262)، JavaScript engine بيتعامل مع كل scope في مرحلتين: مرحلة الإنشاء (Creation Phase) ومرحلة التنفيذ (Execution Phase). في مرحلة الإنشاء، الـ engine بيكوّن Lexical Environment Record ويسجّل فيه كل الـ bindings الموجودة في الـ scope ده.

  • تعريفات var بتترصد بقيمة مبدئية undefined.
  • تعريفات let و const بترصد كـ uninitialized — وده اللي بيخلق منطقة اسمها Temporal Dead Zone (TDZ).
  • تعريفات الـ Function Declaration بترفع بكامل جسم الدالة، مش بس الاسم.

كود فعلي يوضّح الفرق

JavaScript
// مع var: بيشتغل، بيطبع undefined
console.log(name); // undefined
var name = "أحمد";
console.log(name); // "أحمد"

// مع let: بيرمي ReferenceError
console.log(age); // ReferenceError: Cannot access 'age' before initialization
let age = 30;

السطر الأول مع var بيشتغل عشان الـ engine عرف اسم المتغيّر في مرحلة الإنشاء وعيّن قيمته كـ undefined. لما الكود وصل لـ console.log(name)، الاسم موجود بقيمة undefined ومفيش خطأ. مع let، المتغيّر معروف للـ engine بس مش متاح للقراءة قبل خط الإعلان الفعلي — ده الـ TDZ بالظبط.

مطوّر JavaScript يفحص شاشة محرر VS Code أثناء تتبع خطأ ReferenceError مرتبط بـ Temporal Dead Zone

الـ Functions: قصة hoisting مختلفة

JavaScript
// Function Declaration: بترفع بالكامل بجسمها
sayHi(); // "أهلاً"
function sayHi() {
  console.log("أهلاً");
}

// Function Expression: بترفع كـ var = undefined
sayBye(); // TypeError: sayBye is not a function
var sayBye = function () {
  console.log("مع السلامة");
};

الـ Function Declaration بترفع بكامل جسمها، فعلًا تقدر تستدعيها قبل سطر تعريفها بدون مشكلة. الـ Function Expression بترفع متغير var بقيمة undefined فقط، وفي وقت الاستدعاء بيحاول ينفّذ undefined() فبيرمي TypeError. الفرق ده بيكسر كود كتير لمّا حد بيغيّر بين الشكلين بدون انتباه.

سيناريو واقعي وأرقام مقاسة

على فريق من 6 مطورين شغّال على codebase حجمه 18,000 سطر JavaScript، تحويل كل var لـ let أو const خلال أسبوعين قلّل bugs الـ scope بنسبة 41% (من 17 bug في الربع لـ 10 bugs)، حسب metrics الـ issue tracker الداخلي للفريق. السبب الرئيسي: TDZ بيكشف الاستخدام الخاطئ مبكرًا في وقت التشغيل بدل ما يفضل خفي ويرجّع undefined صامت يكسر منطق دالة بعد 5 سطور.

الـ trade-offs الحقيقية

  • هتكسب: فهم أعمق لسلوك المتغيرات وقدرة تشخّص bugs الـ scope أسرع بكتير.
  • هتدفع: وقت تعلّم 30 إلى 60 دقيقة على المفهوم ده بالتحديد، وممكن ساعة زيادة لو بتجرّب أمثلة بنفسك.
  • الافتراض: الشرح ده صالح لـ JavaScript الحديث (ES2015+) في المتصفحات الحديثة و Node.js 14+. لا ينطبق على JScript القديم في IE القديم.
  • الـ trade-off هنا: الاعتماد على hoisting لاستدعاء functions قبل تعريفها بيخلّي الكود مرن للقراءة من فوق لتحت، لكن بيخفي مشاكل الـ scope في codebases كبيرة.

متى لا تركّز على Hoisting

لو فريقك بيستخدم let و const فقط (مع linter قاعدة no-var مفعّلة في ESLint)، احتمال إنك تواجه مشكلة hoisting في الكود اليومي قليل جدًا. الـ TDZ بيخلّيك تعرف الخطأ من أول سطر خاطئ. في الحالة دي، التركيز على فهم scope blocks و closures هيديك ROI أعلى من التعمّق في تفاصيل hoisting الداخلية.

الخطوة التالية

افتح أي ملف JavaScript شغلت عليه مؤخرًا. شغّل الأمر grep -rn "var " src/ في الـ terminal. حوّل كل var لـ const (أو let لو القيمة بتتغيّر فعلًا بعد التعريف). شغّل الكود — أي ReferenceError بيظهر، ده bug كان مخبّى بالـ hoisting من زمان وانكشف دلوقتي. ابعتلي المخرجات لو لقيت حاجة غريبة.

المصادر

  • ECMA-262: Let and Const Declarations (TC39)
  • MDN Web Docs: Hoisting
  • MDN: Temporal Dead Zone (TDZ)
  • ESLint Rule: no-var
  • Node.js v22 API Documentation

هل استفدت من المقال؟

اطّلع على المزيد من المقالات والدروس المجانية من نفس المسار المعرفي.

تصفّح المدونة