| النوع | يُرفع؟ | القيمة قبل التعريف |
|---|---|---|
| var | نعم | undefined |
| let / const | نعم (لكن TDZ) | ReferenceError |
| Function Declaration | نعم بالكامل | الدالة تعمل بشكل طبيعي |
| Function Expression | حسب نوع المتغير | ReferenceError أو undefined |
الـ Hoisting هو سلوك داخلي في محرك جافاسكريبت يجعل تصريحات (Declarations) المتغيرات والدوال تُرفع فعلياً إلى أعلى نطاقها قبل تنفيذ أي كود، رغم أنك كتبتها في مكان لاحق. المهم فهمه هنا أن "التصريح" فقط يُرفع، وليس "التعيين" (القيمة).
مع var، يُرفع التصريح ويُهيَّأ المتغير تلقائياً بقيمة undefined حتى يصل التنفيذ لسطر التعيين الفعلي — لهذا يمكنك استخدام متغير var قبل سطر تعريفه دون خطأ، لكنه سيكون undefined وليس القيمة المتوقعة.
مع let وconst، يحدث Hoisting أيضاً لكن بطريقة مختلفة تماماً: يُرفع التصريح لكن المتغير يبقى في منطقة تُسمى "Temporal Dead Zone" (منطقة ميتة مؤقتاً) من بداية النطاق حتى سطر التعريف الفعلي. أي محاولة لاستخدام المتغير في هذه المنطقة تُنتج خطأ ReferenceError صريحاً، وهذا أفضل بكثير من undefined الصامت لأنه يكشف الأخطاء مبكراً.
إعلانات الدوال (Function Declarations) تخضع لـ Hoisting الكامل — يُرفع التصريح والتعريف الكامل للدالة معاً، لذا يمكن استدعاء الدالة قبل مكان تعريفها في الكود بأمان تام. لكن تعبيرات الدوال (Function Expressions) وDoدوال Arrow لا تتمتع بهذه الميزة، لأنها في جوهرها متغيرات (let/const/var) تُسند لها دالة كقيمة، وتخضع لنفس قواعد Hoisting الخاصة بنوع التصريح المستخدم.
| 1 | console.log(س); // undefined (وليس خطأ) بسبب Hoisting مع var |
| 2 | var س = 5; |
| 3 | |
| 4 | // console.log(ص); // ❌ ReferenceError: Cannot access before initialization |
| 5 | let ص = 10; |
| 6 | |
| 7 | مرحبا(); // ✅ يعمل بأمان: Function Declaration مرفوعة بالكامل |
| 8 | function مرحبا() { |
| 9 | console.log("مرحباً!"); |
| 10 | } |
مثال 1: مقارنة عملية بين var و let في Hoisting
| 1 | // var مقابل let في الـ Hoisting |
| 2 | function اختبار() { |
| 3 | console.log(أ); // undefined |
| 4 | var أ = 1; |
| 5 | |
| 6 | try { |
| 7 | console.log(ب); // خطأ |
| 8 | let ب = 2; |
| 9 | } catch (خطأ) { |
| 10 | console.log("خطأ:", خطأ.message); |
| 11 | } |
| 12 | } |
| 13 | اختبار(); |
مثال 2: الفرق بين Function Declaration و Expression في Hoisting
| 1 | // Function Declaration مرفوعة بالكامل، لكن Function Expression لا |
| 2 | حساب_عادي(); // ✅ يعمل |
| 3 | function حساب_عادي() { |
| 4 | console.log("أعمل حتى قبل تعريفي في الكود!"); |
| 5 | } |
| 6 | |
| 7 | // حساب_سهمي(); // ❌ خطأ: Cannot access before initialization |
| 8 | const حساب_سهمي = () => { |
| 9 | console.log("لا أعمل قبل تعريفي"); |
| 10 | }; |