تعبير الدالة مقابل الإعلان: أيهما تختار في JavaScript؟

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

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

ابدأ الدورة

لماذا هذا السؤال يحير حتى المطورين ذوي الخبرة؟

\n

إذا كنت قد كتبت في JavaScript ولو مرة واحدة، فمن المحتمل أنك صادفت كلا الطريقتين لتعريف الدوال. تبدو متشابهة، لكنها تتصرف بشكل مختلف تمامًا. على Stack Overflow، جمع هذا السؤال آلاف المشاهدات وعشرات الصفحات من النقاشات. لماذا؟ لأن عدم فهم الفرق بين var functionName = function() {} و function functionName() {} يؤدي إلى أخطاء يصعب تتبعها.

\n

اليوم سنحسم هذا الموضوع مرة وإلى الأبد. ستتعرف على ما هو إعلان الدالة و تعبير الدالة، وكيف يعمل الرفع (hoisting)، ومتى تستخدم أي طريقة. هيا بنا!

\n\n

ما الذي يخفيه التركيب النحوي؟

\n

لنبدأ بالأساسيات. الخيار الأول هو إعلان الدالة:

\n
function greet() {\n    console.log('مرحبًا!');\n}
\n

الخيار الثاني هو تعبير الدالة:

\n
const greet = function() {\n    console.log('مرحبًا!');\n};
\n

لاحظ: في الحالة الأولى، للدالة اسم وتكون في بداية السطر. في الحالة الثانية، نُسند دالة مجهولة إلى المتغير greet. لكن الأمر الأكثر إثارة يبدأ عندما ننظر إلى كيفية معالجة JavaScript لهذه التعريفات.

\n\n

الفرق الرئيسي: الرفع (Hoisting)

\n

الرفع هو آلية في JavaScript، حيث يتم نقل تعريفات المتغيرات والدوال إلى أعلى نطاق الرؤية الخاص بها قبل تنفيذ الكود. لكنه يعمل بشكل مختلف مع الإعلان والتعبير.

\n\n

إعلان الدالة يُرفع بالكامل

\n

عند استخدام function functionName() {}، تقوم JavaScript برفع تعريف الدالة بالكامل إلى الأعلى. هذا يعني أنه يمكنك استدعاء الدالة قبل تعريفها في الكود:

\n
sayHello(); // "مرحبًا!"\n\nfunction sayHello() {\n    console.log('مرحبًا!');\n}
\n

سيتم تنفيذ الكود دون أخطاء. هذا مريح، لكنه قد يربك المبتدئين.

\n\n

تعبير الدالة لا يُرفع

\n

مع var functionName = function() {} القصة مختلفة. يتم رفع تعريف المتغير فقط، وليس قيمته. تبقى الدالة في مكانها:

\n
sayHello(); // TypeError: sayHello is not a function\n\nvar sayHello = function() {\n    console.log('مرحبًا!');\n};
\n

لماذا يحدث ذلك؟ لأن var يرفع تعريف المتغير sayHello (بقيمة undefined)، ويتم تعيين الدالة فقط في السطر الذي يحتوي على التعبير. لذلك، قبل هذا السطر، sayHello هو undefined، ومحاولة استدعائه كدالة تؤدي إلى خطأ.

\n\n

بالمناسبة، إذا استبدلت var بـ let أو const، سيكون الخطأ مختلفًا — ReferenceError: Cannot access 'sayHello' before initialization. هذا مرتبط بأن let و const لا يتم تهيئتهما حتى لحظة التعريف (ما يسمى بـ "المنطقة الميتة المؤقتة").

\n\n

نطاق الرؤية: حجر عثرة آخر

\n

كل من إعلان الدالة و تعبير الدالة يخضعان لقواعد نطاق الرؤية. لكن هناك فارق دقيق.

\n\n

إعلان الدالة مرئي داخل الكتلة

\n

على الرغم من أن إعلان الدالة يُرفع، إلا أن نطاق رؤيته محدود بالكتلة (في الوضع الصارم):

\n
'use strict';\nif (true) {\n    function greet() {\n        console.log('داخل الكتلة');\n    }\n    greet(); // "داخل الكتلة"\n}\ngreet(); // ReferenceError: greet is not defined (في الوضع الصارم)
\n

في الوضع غير الصارم، قد "يتسرب" هذا التعريف إلى الخارج، لكن لا ينبغي الاعتماد على ذلك.

\n\n

تعبير الدالة يعيش في متغيره

\n

مع تعبير الدالة، كل شيء قابل للتوقع: الدالة متاحة فقط حيث يكون المتغير متاحًا. إذا تم نق

المدونات

توصيات الكتب