let مقابل var في JavaScript: أيهما تختار للسرعة والأداء؟

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

let مقابل var: حرب عوالم أم تطور JavaScript؟

\n\n

هل سبق لك أن كتبت كودًا بلغة JavaScript وأمسكت بنفسك تفكر: «لماذا يتصرف هذا المتغير بهذه الطريقة الغريبة؟» أو الأسوأ من ذلك، واجهت خطأً يختفي عند استبدال var بـ let؟ مرحبًا بك في النادي. سؤال «ما الفرق بين "let" و "var"؟» على Stack Overflow يجمع مئات الآلاف من المشاهدات ليس من قبيل الصدفة - إنه أحد أكثر الفخاخ شيوعًا للمبتدئين وحتى المطورين ذوي الخبرة.

\n\n

اليوم لن نقوم فقط بسرد الاختلافات. سننظر تحت الغطاء: سنفهم كيف يؤثر let و var على أداء كودك، والتحسين في المحركات الحديثة (V8، SpiderMonkey) ولماذا الاختيار بينهما ليس مجرد مسألة أسلوب، بل كفاءة أيضًا. استعدوا، سيكون الأمر مثيرًا.

\n\n

باختصار عن الأساسيات: النطاق والرفع (hoisting)

\n\n

قبل أن نتحدث عن الأداء، دعنا نتذكر الأساسيات. هناك ثلاثة اختلافات رئيسية بين var و let تغير كل شيء.

\n\n

1. النطاق (Scope)

\n\n
    \n
  • var - له نطاق دالة. إذا تم تعريف المتغير داخل دالة، فهو مرئي في جميع أنحاء الدالة. إذا كان خارجها، فهو عام.
  • \n
  • let - له نطاق كتلة. يعيش فقط داخل الأقواس المتعرجة الأقرب {} (حلقة، شرط، كتلة).
  • \n
\n\n
// مثال مع var\nif (true) {\n    var x = 10;\n}\nconsole.log(x); // 10 — المتغير "تسرب" خارج الكتلة\n\n// مثال مع let\nif (true) {\n    let y = 20;\n}\nconsole.log(y); // ReferenceError: y is not defined\n
\n\n

2. الرفع (Hoisting) والمنطقة الميتة المؤقتة (Temporal Dead Zone - TDZ)

\n\n

كلا المتغيرين «يُرفعان» (hoisting)، لكنهما يتصرفان بشكل مختلف.

\n\n
    \n
  • var: يتم رفع التصريح إلى أعلى النطاق ويتم تهيئته بقيمة undefined. يمكنك الوصول إلى المتغير قبل تصريحه (لكنك ستحصل على undefined).
  • \n
  • let: يتم رفع التصريح، لكنه لا يُهيأ. حتى لحظة التصريح الفعلي، يكون المتغير في «منطقة ميتة مؤقتة» (Temporal Dead Zone). أي محاولة للوصول إليه تسبب ReferenceError.
  • \n
\n\n
// var — "undefined" آمن\nconsole.log(a); // undefined\nvar a = 5;\n\n// let — خطأ في TDZ\nconsole.log(b); // ReferenceError: Cannot access 'b' before initialization\nlet b = 10;\n
\n\n

3. إعادة التصريح

\n\n
    \n
  • var - يمكن إعادة التصريح به أي عدد من المرات في نفس النطاق. لن يحدث خطأ.
  • \n
  • let - إعادة التصريح في نفس النطاق ستسبب SyntaxError.
  • \n
\n\n
var z = 1;\nvar z = 2; // جيد\n\nlet w = 1;\nlet w = 2; // SyntaxError: Identifier 'w' has already been declared\n
\n\n

والآن عن الموضوع الرئيسي: الأداء والتحسين

\n\n

يعتقد الكثيرون: «بما أن let هو المعيار الجديد، فهو أبطأ من var؟» أو العكس: «let أفضل، إذن هو أسرع». الحقيقة، كالعادة، في المنتصف وتعتمد على السياق.

\n\n

كيف تحسن المحركات المتغيرات

\n\n

محركات JavaScript الحديثة (V8 في Chrome/Node.js، SpiderMonkey في Firefox) تترجم الكود إلى كود آلة باستخدام مترجمات JIT. تستخدم هذه المحركات استدلالات للتحسين.

\n\n
    \n
  • var: بسبب نطاق الدالة وإمكانية إعادة التعريف العشوائي، يصعب على المحرك وضع افتراضات حول نوع المتغير. غالبًا ما ينشئ كائنات «ثقيلة» VariableObject تخزن المتغيرات في الذاكرة الديناميكية.
  • \n
  • let: نطاق الكتلة ومنع إعادة التصريح يعطيان المحرك أفضلية في التحسين. يمكن للمحرك تخصيص مساحة ثابتة للمتغير، مما يقلل الحمل على جمع القمامة (garbage collection) ويسرع الوصول.
  • \n

المدونات

توصيات الكتب