وظائف جافا سكريبت. جافا سكريبت التعبيرية: تعمل الوظائف كقيم

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

دونالد كنوث

لقد رأيت بالفعل استدعاءات لوظائف مثل التنبيه . الوظائف هي خبز وزبدة برمجة جافا سكريبت. تحظى فكرة تغليف جزء من البرنامج وتسميته كمتغير بشعبية كبيرة. إنها أداة لبناء البرامج الكبيرة، وتقليل التكرار، وتسمية الإجراءات الفرعية، وعزل الإجراءات الفرعية عن بعضها البعض.

الاستخدام الأكثر وضوحًا للوظائف هو إنشاء قاموس جديد. إن اختراع كلمات للنثر البشري العادي هو أمر سيئ. وهذا ضروري في لغة البرمجة.

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

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

فار سكوير = دالة(x) (return x * x; ); console.log(square(12)); // → 144

يتم إنشاء دالة بواسطة تعبير يبدأ بالكلمة الأساسية للوظيفة. تحتوي الوظائف على مجموعة من المعلمات (في هذه الحالة، x فقط)، ونص يحتوي على التعليمات التي يجب تنفيذها عند استدعاء الوظيفة. يتم وضع نص الدالة دائمًا بين قوسين متعرجين، حتى لو كان يتكون من عبارة واحدة.

قد تحتوي الدالة على عدة معلمات أو لا تحتوي على أي معلمات على الإطلاق. في المثال التالي، لا يحتوي makeNoise على قائمة من المعلمات، لكن الطاقة لها اثنان:

var makeNoise = function() ( console.log("Shit!"); ); خلق ضجة()؛ // → خريا! فار باور = دالة (أساس، أس) ( نتيجة فار = 1؛ لـ (فار كونت = 0؛ كونت< exponent; count++) result *= base; return result; }; console.log(power(2, 10)); // → 1024

تُرجع بعض الوظائف قيمة، مثل power وsquare، والبعض الآخر لا يفعل ذلك، مثل makeNoise، الذي ينتج عنه تأثير جانبي فقط. تحدد عبارة الإرجاع القيمة التي يتم إرجاعها بواسطة الدالة. عندما تصل معالجة البرنامج إلى هذه التعليمات، فإنه يخرج على الفور من الوظيفة ويعيد هذه القيمة إلى المكان الموجود في الكود الذي تم استدعاء الوظيفة منه. العودة بدون تعبير ترجع غير محددة .

المعلمات والنطاق معلمات الوظيفة هي نفس المتغيرات، ولكن يتم تعيين قيمها الأولية عند استدعاء الوظيفة، وليس في الكود الخاص بها.

من الخصائص المهمة للوظائف أن المتغيرات التي تم إنشاؤها داخل الوظيفة (بما في ذلك المعلمات) تكون محلية لتلك الوظيفة. هذا يعني أنه في مثال الطاقة، سيتم إنشاء متغير النتيجة في كل مرة يتم فيها استدعاء الوظيفة، ولن يكون لهذه التجسيدات الفردية أي علاقة ببعضها البعض.

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

يوضح التعليمة البرمجية التالية هذا. يقوم بتعريف واستدعاء وظيفتين تقومان بتعيين قيمة للمتغير x. يعلن الأول أنه محلي، وبالتالي تغيير المتغير المحلي فقط. والثاني لا يعلن، لذا فإن العمل مع x داخل الوظيفة يشير إلى المتغير العام x المحدد في بداية المثال.

فار س = "خارج"; var f1 = function() ( var x = "داخل f1"; ); f1(); console.log(x); // → خارج var f2 = function() ( x = "داخل f2"; ); f2(); console.log(x); // → داخل f2

يساعد هذا السلوك على منع التفاعلات غير المقصودة بين الوظائف. إذا تم استخدام جميع المتغيرات في أي مكان في البرنامج، فسيكون من الصعب للغاية التأكد من عدم استخدام متغير واحد لأغراض مختلفة. وإذا كنت ستعيد استخدام متغير، فسوف تواجه تأثيرات غريبة عندما يفسد كود الطرف الثالث قيم المتغير الخاص بك. من خلال معالجة المتغيرات الوظيفية المحلية بحيث تكون موجودة فقط داخل الوظيفة، تتيح اللغة العمل مع الوظائف كما لو كانت أكوانًا صغيرة منفصلة، ​​مما يسمح لك بعدم القلق بشأن الكود بأكمله.

نطاق متداخل يميز جافا سكريبت أكثر من مجرد بين المتغيرات العالمية والمحلية. يمكن تعريف الوظائف ضمن الوظائف، مما يؤدي إلى مستويات متعددة من المنطقة.

على سبيل المثال، تحتوي الدالة التالية التي لا معنى لها على وظيفتين إضافيتين بالداخل:

var Landscape = function() ( var result = ""; var flat = function(size) ( for (var count = 0; count< size; count++) result += "_"; }; var mountain = function(size) { result += "/"; for (var count = 0; count < size; count++) result += """; result += "\\"; }; flat(3); mountain(4); flat(6); mountain(1); flat(1); return result; }; console.log(landscape()); // → ___/""""\______/"\_

ترى الدالتان المسطحة والجبلية متغير النتيجة لأنهما داخل الدالة التي تحدده. لكن لا يمكنهم رؤية متغيرات العدد الخاصة ببعضهم البعض لأن متغيرات إحدى الوظائف تقع خارج نطاق الوظيفة الأخرى. والبيئة خارج الدالة الأفقية لا ترى أيًا من المتغيرات المحددة داخل هذه الدالة.

باختصار، داخل كل نطاق محلي، يمكنك رؤية كافة النطاقات التي تحتوي عليه. يتم تحديد مجموعة المتغيرات المتوفرة داخل الدالة حسب الموقع الذي تم إعلان الدالة فيه في البرنامج. جميع المتغيرات من الكتل المحيطة بتعريف الوظيفة مرئية - بما في ذلك تلك المحددة في المستوى العلويفي البرنامج الرئيسي. هذا النهج في النطاقات يسمى المعجمي.

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

فار شيء = 1؛ ( var thing = 2; // افعل شيئًا باستخدام المتغير Something... ) // الخروج من الكتلة...

لكن هناك شيء ما داخل الكتلة هو نفس المتغير الموجود في الخارج. على الرغم من أن مثل هذه الكتل مسموح بها، إلا أنه من المنطقي استخدامها فقط لعبارات if والحلقات.

إذا كان هذا يبدو غريبا بالنسبة لك، فأنت لست الوحيد الذي يعتقد ذلك. قدم جافا سكريبت 1.7 الكلمة الأساسية Let، التي تعمل مثل var ولكنها تنشئ متغيرات محلية لأي كتلة معينة، وليس فقط الوظيفة.

الوظائف كقيم تُستخدم أسماء الوظائف عادةً كاسم لجزء من البرنامج. يتم تعيين مثل هذا المتغير مرة واحدة ولا يتغير. لذلك من السهل الخلط بين الوظيفة واسمها.

لكن هذين شيئين مختلفين. يمكن استخدام استدعاء الدالة كمتغير بسيط - على سبيل المثال، يمكن استخدامه في أي تعبير. من الممكن تخزين استدعاء دالة في متغير جديد، وتمريره كمعلمة إلى دالة أخرى، وما إلى ذلك. كما أن المتغير الذي يخزن استدعاء الدالة يظل متغيرًا عاديًا ويمكن تغيير قيمته:

var LaunchMissiles = function(value) ( ​​​​missileSystem.launch("or!"); ); if (safeMode) LaunchMissiles = function(value) (/* Cancel */);

في الفصل الخامس، سنناقش الأشياء الرائعة التي يمكنك القيام بها عن طريق تمرير استدعاءات الوظائف إلى وظائف أخرى.

إعلان الوظائف هناك نسخة أقصر من التعبير "var Square = function...". يمكن استخدام الكلمة الأساسية function في بداية العبارة:

مربع الوظيفة(x) (إرجاع x * x;)

هذا هو إعلان الوظيفة. تحدد العبارة المتغير المربع وتعين الوظيفة المحددة له. حتى الان جيدة جدا. هناك مأزق واحد فقط في مثل هذا التعريف.

Console.log("المستقبل يقول:"، المستقبل())؛ وظيفة المستقبل () (إرجاع "لا نزال ليس لدينا سيارات طائرة."؛)

يعمل هذا الرمز على الرغم من أن الوظيفة مذكورة أسفل الكود الذي يستخدمها. وذلك لأن إعلانات الوظائف ليست جزءًا من التنفيذ العادي للبرنامج من أعلى إلى أسفل. يتم "نقلها" إلى أعلى نطاقها ويمكن استدعاؤها بواسطة أي رمز في هذا النطاق. يكون هذا مناسبًا في بعض الأحيان لأنه يمكنك كتابة التعليمات البرمجية بالترتيب الأكثر منطقية دون الحاجة إلى القلق بشأن الاضطرار إلى تحديد جميع الوظائف المذكورة أعلاه حيث يتم استخدامها.

ماذا يحدث إذا وضعنا إعلان دالة داخل كتلة شرطية أو حلقة؟ ليس عليك أن تفعل ذلك. تاريخيًا، تعاملت منصات JavaScript المختلفة مع مثل هذه الحالات بشكل مختلف، ويحظر معيار اللغة الحالي ذلك. إذا كنت تريد تشغيل برامجك بشكل تسلسلي، فاستخدم إعلانات الوظائف فقط ضمن الوظائف الأخرى أو البرنامج الرئيسي.

مثال الدالة() ( الدالة a() () // عادي إذا (شيء) ( الدالة b() () // Ay-yay-yay! ) )

Call Stack من المفيد إلقاء نظرة فاحصة على كيفية عمل أمر التنفيذ مع الوظائف. هنا برنامج بسيطمع استدعاءات متعددة الوظائف:

وظيفة تحية(من) (console.log("Hello, " + who); )gree("Semyon"); console.log("بوكيدا");

تتم معالجته على النحو التالي: يؤدي استدعاء الترحيب إلى انتقال التمرير إلى بداية الوظيفة. فهو يستدعي وظيفة console.log المضمنة، التي تعترض التحكم، وتقوم بعملها، وتعيد التحكم. ثم يصل إلى نهاية السلام، ويعود إلى المكان الذي نودي منه. السطر التالي يستدعي console.log مرة أخرى.

يمكن إظهار ذلك بشكل تخطيطي مثل هذا:

أعلى تحية console.log تحية أعلى console.log أعلى

ولأن الوظيفة يجب أن تعود إلى المكان الذي تم استدعاؤها منه، يجب أن يتذكر الكمبيوتر السياق الذي تم استدعاء الوظيفة منه. في إحدى الحالات، يجب أن يعود console.log مرة أخرى للترحيب. وفي أخرى تعود إلى نهاية البرنامج.

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

يتطلب تخزين المكدس مساحة في الذاكرة. عندما تصبح المكدس كبيرة جدًا، سيتوقف الكمبيوتر عن التنفيذ ويقول شيئًا مثل "تجاوز سعة المكدس" أو "الكثير من العودية". يوضح التعليمة البرمجية التالية ذلك - فهو يطرح على الكمبيوتر سؤالاً معقدًا للغاية، مما يؤدي إلى قفزات لا نهاية لها بين وظيفتين. بتعبير أدق، سيكون الأمر عبارة عن قفزات لا نهائية إذا كان الكمبيوتر يحتوي على مكدس لا نهائي. في الواقع، المكدس يفيض.

وظيفة الدجاج () (إرجاع البيضة () ؛) وظيفة البيض () (إرجاع الدجاج () ؛) console.log(chicken () + "جاء أولاً."); // → ؟؟

الوسيطات الاختيارية الكود التالي قانوني تمامًا ويعمل بدون مشاكل:

تنبيه ("مرحبا"، "مساء الخير"، "مرحبا بالجميع!")؛

رسميًا، تأخذ الدالة وسيطة واحدة. ومع ذلك، عندما يتم تحديها بهذه الطريقة، فإنها لا تشتكي. تتجاهل بقية الحجج وتظهر "مرحبًا".

JavaScript مهتم جدًا بعدد الوسائط التي تم تمريرها إلى الوظيفة. إذا قمت بنقل الكثير، سيتم تجاهل تلك الإضافية. عدد قليل جدًا وسيتم تعيين القيمة غير المحددة للمفقودين.

الجانب السلبي لهذا النهج هو أنه من الممكن - بل ومن المحتمل - تمرير عدد خاطئ من الوسائط إلى دالة دون أن يشكو أي شخص من ذلك.

الميزة هي أنه يمكنك إنشاء وظائف تأخذ وسيطات اختيارية. على سبيل المثال، في الإصدار التالي من دالة الطاقة، يمكن استدعاؤها باستخدام وسيطتين أو واحدة - في الحالة الأخيرة، سيكون الأس مساويًا لاثنين، وتعمل الدالة مثل المربع.

قوة الدالة (الأساس، الأس) ( إذا (الأس == غير محدد) الأس = 2؛ نتيجة فار = 1؛ لـ (فار العد = 0؛ العد< exponent; count++) result *= base; return result; } console.log(power(4)); // → 16 console.log(power(4, 3)); // → 64

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

Console.log("R", 2, "D", 2); // → ص 2 د 2

عمليات الإغلاق إن القدرة على استخدام استدعاءات الوظائف كمتغيرات، إلى جانب حقيقة إنشاء المتغيرات المحلية من جديد في كل مرة يتم فيها استدعاء دالة، يقودنا إلى سؤال مثير للاهتمام. ماذا يحدث للمتغيرات المحلية عندما تتوقف الدالة عن العمل؟

يوضح المثال التالي هذه المشكلة. تعلن عن وظيفة WrapValue، التي تقوم بإنشاء متغير محلي. ثم تقوم بإرجاع دالة تقرأ هذا المتغير المحلي وترجع قيمته.

الدالة WrapValue(n) ( var localVariable = n; return function() ( return localVariable; ); ) var Wrap1 = WrapValue(1); فار التفاف2 = التفافValue(2); console.log(wrap1()); // → 1 console.log(wrap2()); // → 2

وهذا صحيح ويعمل كما ينبغي - يبقى الوصول إلى المتغير. علاوة على ذلك، يمكن أن توجد مثيلات متعددة لنفس المتغير في نفس الوقت، مما يؤكد أيضًا حقيقة أنه يتم إعادة إنشاء المتغيرات المحلية مع كل استدعاء دالة.

تسمى هذه القدرة على العمل مع مرجع لمثيل متغير محلي بالإغلاق. تسمى الوظيفة التي تغلق المتغيرات المحلية بالإغلاق. فهو لا يحررك من القلق بشأن فترات الحياة المتغيرة فحسب، بل يسمح لك أيضًا باستخدام الوظائف بشكل إبداعي.

مع تعديل بسيط، نحول مثالنا إلى دالة تقوم بضرب الأرقام في أي رقم محدد.

مضاعف الوظيفة (العامل) ( دالة الإرجاع (الرقم) ( رقم الإرجاع * العامل؛ )؛ ) var مرتين = المضاعف (2)؛ console.log(twice(5)); // → 10

لم تعد هناك حاجة لمتغير منفصل مثل localVariable من مثال WrapValue. لأن المعلمة هي في حد ذاتها متغير محلي.

سوف يستغرق الأمر ممارسة لبدء التفكير بهذه الطريقة. النموذج العقلي الجيد هو تخيل أن الوظيفة تجمد الكود في جسمها وتغلفه في حزمة. عندما ترى وظيفة الإرجاع (...) (...)، فكر في الأمر كلوحة تحكم لجزء من التعليمات البرمجية المجمدة لاستخدامها لاحقًا.

في مثالنا، يقوم المضاعف بإرجاع جزء مجمد من التعليمات البرمجية، والذي نقوم بتخزينه في المتغير double. يستدعي السطر الأخير الوظيفة الموجودة في المتغير، مما يؤدي إلى تنشيط الكود المخزن (رقم الإرجاع * العامل؛). لا يزال بإمكانه الوصول إلى متغير العامل الذي تم تعريفه عند استدعاء المضاعف، كما يمكنه أيضًا الوصول إلى الوسيطة التي تم تمريرها أثناء إزالة الصقيع (5) كمعلمة رقمية.

العودية قد تستدعي الوظيفة نفسها طالما أنها تحرص على عدم تجاوز سعة المكدس. هذه الوظيفة تسمى العودية. فيما يلي مثال على التنفيذ البديل للأس:

وظيفة الطاقة (الأساس، الأس) (إذا (الأس == 0) تُرجع 1؛ وإلا تُرجع القاعدة * الطاقة (الأساس، الأس - 1)؛) console.log(power(2, 3)); // → 8

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

ومع ذلك، فإن هذا التنفيذ به مشكلة - في بيئة JavaScript العادية، يكون أبطأ 10 مرات من الإصدار الذي يحتوي على حلقة. إن السير عبر الحلقة أرخص من استدعاء دالة.

معضلة السرعة مقابل الأناقة مثيرة للاهتمام للغاية. هناك فجوة معينة بين الراحة للبشر والراحة للآلات. يمكن تسريع أي برنامج بجعله أكبر وأكثر تعقيدًا. مطلوب من المبرمج إيجاد التوازن المناسب.

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

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

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

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

لكن العودية ليست دائمًا مجرد بديل أقل كفاءة للحلقات. بعض المشاكل أسهل في الحل مع التكرار. غالبًا ما يكون هذا اجتياز عدة فروع للشجرة، كل منها يمكن أن يتفرع.

إليك اللغز: يمكنك الحصول على عدد لا نهائي من الأرقام عن طريق البدء بالرقم 1، ثم إضافة 5 أو الضرب في 3. كيف نكتب دالة تحاول، عند إعطاء رقم، إيجاد تسلسل عمليات الجمع والضرب؟ التي تؤدي إلى عدد معين؟ على سبيل المثال، يمكن الحصول على الرقم 13 عن طريق ضرب 1 في 3 أولاً ثم إضافة 5 مرتين. ولا يمكن الحصول على الرقم 15 بهذه الطريقة على الإطلاق.

الحل العودي:

دالة findSolution(target) ( وظيفة find(start, History) ( if (start == target) تُرجع التاريخ؛ وإلا إذا (start > target) تُرجع قيمة فارغة؛ وإلا تُرجع find(start + 5, "(" + History + " + 5)") || find(start * 3, "(" + History + " * 3)"); ) return find(1, "1"); ) console.log(findSolution(24)); // → (((1 * 3) + 5) * 3)

هذا المثال لا يجد بالضرورة الحل الأقصر - فهو يرضي أي حل. لا أتوقع منك أن تفهم على الفور كيفية عمل البرنامج. لكن دعونا نفهم هذا التمرين الرائع في التفكير التكراري.

وظيفة البحث الداخلية تقوم بالتكرار. يستغرق الأمر وسيطتين - الرقم الحالي وسلسلة تحتوي على سجل لكيفية وصولنا إلى هذا الرقم. وتقوم بإرجاع إما سلسلة توضح تسلسل الخطوات لدينا، أو null.

للقيام بذلك، تقوم الدالة بتنفيذ أحد الإجراءات الثلاثة. إذا كان الرقم المحدد يساوي الهدف، فإن القصة الحالية هي بالضبط الطريق لتحقيق ذلك، لذلك تعود. فإذا كان الرقم المعطى أكبر من الهدف، فلا فائدة من الاستمرار في الضرب والإضافة، لأنه لن يؤدي إلا إلى الزيادة. وإذا لم نصل إلى الهدف بعد، فإن الدالة تحاول كلا المسارين الممكنين بدءًا من الرقم المحدد. تستدعي نفسها مرتين، مرة بكل طريقة. إذا لم تُرجع المكالمة الأولى قيمة فارغة، فسيتم إرجاعها. وفي حالة أخرى، يتم إرجاع الثانية.

لفهم كيفية تحقيق الدالة للتأثير المطلوب بشكل أفضل، دعونا نلقي نظرة على الاستدعاءات التي تجريها لإيجاد حل للرقم 13.

ابحث عن(1, "1") ابحث عن(6, "(1 + 5)") ابحث عن(11, "((1 + 5) + 5)") ابحث عن(16, "(((1 + 5) + 5)" ) + 5)") اكتشاف كبير جدًا(33, "(((1 + 5) + 5) * 3)") اكتشاف كبير جدًا(18, "((1 + 5) * 3)") اكتشاف كبير جدًا( 3، "(1 * 3)") العثور على(8، "((1 * 3) + 5)") العثور على(13، "(((1 * 3) + 5) + 5)") وجدت!

تُظهر المسافة البادئة عمق مكدس الاستدعاءات. في المرة الأولى، تستدعي دالة البحث نفسها مرتين للتحقق من الحلول التي تبدأ بـ (1 + 5) و(1 * 3). يبحث الاستدعاء الأول عن حل يبدأ بـ (1 + 5) ويستخدم التكرار للتحقق من جميع الحلول التي تنتج رقمًا أقل من أو يساوي الرقم المطلوب. لم يتم العثور عليه وإرجاعه فارغًا. ثم العامل || وينتقل إلى استدعاء دالة يفحص الخيار (1 * 3). نحن محظوظون هنا، لأنه في الاستدعاء العودي الثالث نحصل على 13. يقوم هذا الاستدعاء بإرجاع سلسلة، وكل من || على طول الطريق يمرر هذا الخط إلى أعلى، مما يؤدي إلى إرجاع الحل.

الوظائف المتنامية هناك طريقتان أكثر أو أقل طبيعية لإدخال الوظائف في البرنامج.

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

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

إن مدى صعوبة تسمية وظيفة ما يوضح مدى فهمك لوظائفها. لنأخذ مثالا. نحتاج إلى كتابة برنامج يطبع رقمين، عدد الأبقار والدجاج في المزرعة، متبوعًا بكلمتي "أبقار" و"دجاج". تحتاج إلى إضافة أصفار إلى الأرقام الموجودة أمامك بحيث يشغل كل منها ثلاثة مواضع بالضبط.

007 أبقار 011 دجاج

من الواضح أننا بحاجة إلى دالة تحتوي على وسيطتين. لنبدأ بالترميز.
// طباعة وظيفة FarmInventory printFarmInventory(cows, Chicken) ( var CowString = String(cows); while (cowString.length)< 3) cowString = "0" + cowString; console.log(cowString + " Коров"); var chickenString = String(chickens); while (chickenString.length < 3) chickenString = "0" + chickenString; console.log(chickenString + " Куриц"); } printFarmInventory(7, 11);

إذا أضفنا طول إلى سلسلة، نحصل على طوله. اتضح أن حلقات while تضيف أصفارًا بادئة إلى الأرقام حتى تحصل على سطر مكون من 3 أحرف.

مستعد! ولكن بينما كنا على وشك إرسال الرمز إلى المزارع (مع شيك كبير بالطبع)، اتصل بنا وأخبرنا أن لديه خنازير في مزرعته، وهل يمكننا إضافة عرض لعدد الخنازير إلى برنامج؟

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

// الإخراج مع وظيفة إضافة الأصفار والتسميات printZeroPaddedWithLabel(number, label) ( var numberString = String(number); while (numberString.length< 3) numberString = "0" + numberString; console.log(numberString + " " + label); } // вывестиИнвентаризациюФермы function printFarmInventory(cows, chickens, pigs) { printZeroPaddedWithLabel(cows, "Коров"); printZeroPaddedWithLabel(chickens, "Куриц"); printZeroPaddedWithLabel(pigs, "Свиней"); } printFarmInventory(7, 11, 3);

يعمل! لكن الاسم printZeroPaddedWithLabel غريب بعض الشيء. فهو يجمع بين ثلاثة أشياء - الإخراج، وإضافة الأصفار، والتسمية - في وظيفة واحدة. بدلاً من إدراج جزء متكرر بالكامل في دالة، دعنا نسلط الضوء على مفهوم واحد:

// إضافة وظيفة صفر ZeroPad(number, width) ( var string = String(number); while (string.length)< width) string = "0" + string; return string; } // вывестиИнвентаризациюФермы function printFarmInventory(cows, chickens, pigs) { console.log(zeroPad(cows, 3) + " Коров"); console.log(zeroPad(chickens, 3) + " Куриц"); console.log(zeroPad(pigs, 3) + " Свиней"); } printFarmInventory(7, 16, 3);

تعمل الوظيفة ذات الاسم اللطيف والواضح ZeroPad على تسهيل فهم الكود. ويمكن استخدامه في العديد من المواقف، وليس في حالتنا فقط. على سبيل المثال، لعرض الجداول المنسقة بالأرقام.

إلى أي درجة يجب أن تكون الميزات ذكية ومتعددة الاستخدامات؟ يمكننا كتابة دالة بسيطة تقوم بتضمين رقم بأصفار تصل إلى ثلاثة مواضع، أو دالة معقدة للأغراض العامة لتنسيق الأرقام التي تدعم الكسور والأرقام السالبة ومحاذاة النقاط والحشو وما إلى ذلك.

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

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

يتم استدعاء الدالة المساعدة الأولى في مثال المزرعة، printZeroPaddedWithLabel، لأن لها تأثيرًا جانبيًا: فهي تطبع سلسلة. والثاني، ZeroPad، بسبب القيمة المرجعة. وليس من قبيل الصدفة أن تكون الوظيفة الثانية مفيدة أكثر من الأولى. من الأسهل دمج الوظائف التي تُرجع القيم مع بعضها البعض مقارنة بالوظائف التي تنتج آثارًا جانبية.

الدالة الخالصة هي نوع خاص من دالة إرجاع القيمة التي لا ليس لها أي آثار جانبية فحسب، ولكنها لا تعتمد أيضًا على الآثار الجانبية لبقية الكود - على سبيل المثال، لا تعمل مع المتغيرات العامة التي يمكن أن تكون عن طريق الخطأ تغيرت في مكان آخر. الدالة الخالصة، عند استدعائها بنفس الوسائط، تُرجع نفس النتيجة (ولا تفعل شيئًا آخر) - وهو أمر لطيف جدًا. من السهل العمل معها. يمكن استبدال استدعاء هذه الوظيفة عقليًا بنتيجة عملها، دون تغيير معنى الكود. عندما تريد اختبار مثل هذه الوظيفة، يمكنك ببساطة استدعائها، والتأكد من أنها إذا كانت تعمل في سياق معين، فإنها ستعمل في أي سياق. قد تؤدي الوظائف الأقل نقاءً إلى نتائج مختلفة اعتمادًا على العديد من العوامل، ولها آثار جانبية يصعب اختبارها وتفسيرها.

ومع ذلك، لا يجب أن تشعر بالحرج من كتابة وظائف ليست نقية تمامًا، أو البدء في تنظيف التعليمات البرمجية المقدسة لهذه الوظائف. الآثار الجانبية غالبا ما تكون مفيدة. لا توجد طريقة لكتابة نسخة نظيفة من وظيفة console.log، وهذه الوظيفة مفيدة جدًا. بعض العمليات يكون من الأسهل التعبير عنها باستخدام الآثار الجانبية.

ملخص يوضح لك هذا الفصل كيفية كتابة الوظائف الخاصة بك. عند استخدام الكلمة الأساسية للوظيفة كتعبير، يتم إرجاع مؤشر لاستدعاء الوظيفة. عند استخدامها كتعليمات، يمكنك الإعلان عن متغير عن طريق تعيين استدعاء دالة له.

المفتاح لفهم الوظائف هو النطاق المحلي. المعلمات والمتغيرات المعلنة داخل الدالة تكون محلية بالنسبة لها، ويتم إعادة إنشائها في كل مرة يتم استدعاؤها، ولا تكون مرئية من الخارج. الوظائف المعلنة داخل وظيفة أخرى لها حق الوصول إلى نطاقها.

من المفيد جدًا فصل المهام المختلفة التي يؤديها البرنامج إلى وظائف. ليس عليك أن تكرر ما تقوله، فالوظائف تجعل التعليمات البرمجية أكثر قابلية للقراءة من خلال تقسيمها إلى أجزاء ذات معنى، تمامًا كما تساعد فصول الكتاب وأقسامه في تنظيم النص العادي.

الحد الأدنى من التمارين في الفصل السابق، ذكرنا الدالة Math.min، التي تُرجع أصغر وسيطاتها. الآن يمكننا كتابة مثل هذه الوظيفة بأنفسنا. يكتب وظيفة دقيقة، الذي يأخذ وسيطتين ويعيد الحد الأدنى منهما.

Console.log(min(0, 10)); // → 0 console.log(min(0, -10)); // → -10

العودية لقد رأينا أنه يمكن استخدام عامل التشغيل % (modulo) لتحديد ما إذا كان الرقم (%2) زوجيًا. إليك طريقة أخرى لتعريفها:

الصفر متساوي.
الوحدة غريبة.
أي رقم N له نفس التكافؤ مثل N-2.

كتابة دالة عودية تتم وفقًا لهذه القواعد. يجب أن يقبل رقمًا ويعيد قيمة منطقية.

اختبره عند 50 و75. حاول إعطائه -1. لماذا تتصرف بهذه الطريقة؟ هل من الممكن إصلاحه بطريقة أو بأخرى؟

اختبره على 50 و 75. انظر كيف يتصرف على -1. لماذا؟ هل تستطيعالتفكير في طريقة لإصلاح هذا؟

Console.log(isEven(50)); // → صحيح console.log(isEven(75)); // → خطأ console.log(isEven(-1)); // → ؟؟

عد الفول.

يمكن الحصول على رقم الحرف N لسلسلة ما عن طريق إضافة .charAt(N) ("string".charAt(5)) إليه - بطريقة مشابهة للحصول على طول السلسلة باستخدام .length. ستكون القيمة المرجعة عبارة عن سلسلة تتكون من حرف واحد (على سبيل المثال، "k"). الحرف الأول من السطر له الموضع 0، وهو ما يعني ذلك الحرف الأخيرسيكون الموضع هو string.length - 1. وبعبارة أخرى، سيكون طول السلسلة المكونة من حرفين 2، وستكون مواضع الأحرف الخاصة بها 0 و1.

اكتب دالة countBs التي تأخذ سلسلة كوسيطة وترجع عدد الأحرف "B" الموجودة في السلسلة.

ثم اكتب دالة تسمى countChar، والتي تعمل بشكل يشبه countBs، ولكنها تأخذ معلمة ثانية - الحرف الذي سنبحث عنه في السلسلة (بدلاً من مجرد حساب عدد الأحرف "B"). للقيام بذلك، قم بإعادة صياغة الدالة countBs.

عبارات الانتقال ومعالجة الاستثناءات

فئة أخرى من عوامل JavaScript هي عوامل القفز. كما يوحي الاسم، تتسبب عوامل التشغيل هذه في انتقال مترجم JavaScript إلى موقع آخر في كود البرنامج. تؤدي عبارة Break إلى انتقال المترجم إلى نهاية الحلقة أو أي عبارة أخرى. تؤدي عبارة continue إلى قيام المترجم بتخطي بقية نص الحلقة، والقفز مرة أخرى إلى بداية الحلقة، والبدء في تنفيذ تكرار جديد. تتمتع JavaScript بالقدرة على تسمية العبارات بأسماء، لذا يمكن أن تشير عبارات القطع والمتابعة بوضوح إلى الحلقة أو العبارة الأخرى التي تنتمي إليها.

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

يتم وصف كل عوامل تشغيل القفز هذه بمزيد من التفصيل في الأقسام الفرعية التالية.

علامات التعليمات

يمكن تمييز أي تعليمات بمعرف ونقطتين:

معرف: التعليمات

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

من خلال تعيين اسم للحلقة، يمكن بعد ذلك استخدامه في عبارات الاستراحة والمتابعة، أو داخل الحلقة للخروج منها، أو للانتقال إلى بداية الحلقة إلى التكرار التالي. إن عبارات الاستراحة والمتابعة هي عبارات JavaScript الوحيدة التي يمكن أن تتضمن تسميات، وسنغطيها بمزيد من التفاصيل لاحقًا. فيما يلي مثال على عبارة while ذات تسمية وعبارة continue باستخدام تلك التسمية:

Mainloop: while (token != null) ( // تم حذف رمز البرنامج... تابع mainloop؛ // انتقل إلى التكرار التالي للحلقة المسماة)

يمكن أن يكون المعرف المستخدم كتسمية بيان هو أي معرف JavaScript صالح باستثناء الكلمة المحجوزة. يتم فصل أسماء التصنيفات عن أسماء المتغيرات والوظائف، لذلك يمكن استخدام المعرفات التي تطابق أسماء المتغيرات أو الوظائف كتسميات.

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

بيان كسر

تؤدي عبارة Break إلى الخروج فورًا من الحلقة الأعمق أو عبارة التبديل. لقد رأينا سابقًا أمثلة لاستخدام عبارة Break داخل عبارة Switch. في الحلقات، يتم استخدامه عادةً للخروج فورًا من الحلقة عندما تحتاج الحلقة إلى الإنهاء لسبب ما.

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

var arr = ["a"، "b"، "c"، "d"، "d"]، النتيجة؛ ل (فار ط = 0؛ ط

في JavaScript، يمكنك تحديد اسم التسمية بعد الكلمة الأساسية فاصل (معرف بدون نقطتين):

كسر التسمية_الاسم؛

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

لا يمكنك إدراج حرف سطر جديد بين الكلمة الأساسية فاصل واسم التسمية. وذلك لأن مترجم JavaScript يقوم تلقائيًا بإدراج الفواصل المنقوطة المفقودة: إذا قمت بتقسيم سطر من التعليمات البرمجية بين الكلمة الأساسية Break والتسمية التالية، فسوف يفترض المترجم أنك تقصد الشكل البسيط للبيان بدون التسمية، وسيضيف فاصلة منقوطة.

هناك حاجة إلى عبارة Break المسماة فقط عندما تريد مقاطعة تنفيذ عبارة ليست أقرب حلقة مرفقة أو عبارة تبديل.

متابعة المشغل

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

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

    في حلقة while، يتم التحقق من التعبير المحدد في بداية الحلقة مرة أخرى، وإذا كان صحيحًا، فسيتم تنفيذ جسم الحلقة من البداية.

    تنتقل حلقة do/while إلى نهاية الحلقة، حيث يتم التحقق من الشرط مرة أخرى قبل تنفيذ الحلقة مرة أخرى.

    تقوم حلقة for بتقييم تعبير الزيادة وتقييم تعبير الاختبار مرة أخرى لتحديد ما إذا كان يجب إجراء التكرار التالي.

    في حلقة for/in، تبدأ الحلقة من جديد بتعيين المتغير المحدد لاسم الخاصية التالية.

لاحظ الاختلافات في سلوك عبارة continue في حلقات while وfor. تعود حلقة while مباشرة إلى حالتها، بينما تقوم حلقة for أولاً بتقييم تعبير الزيادة ثم تعود إلى الشرط. يوضح المثال التالي استخدام عبارة continue بدون تسمية للخروج من تكرار الحلقة الحالية للأرقام الزوجية:

مجموع فار = 0؛ // احسب مجموع الأعداد الفردية من 0 إلى 10 for (var i = 0; i

يمكن استخدام عبارة continue، مثل Break، في حلقات متداخلة في نموذج يتضمن تسمية، ومن ثم فإن الحلقة التي يتم إعادة تشغيلها لن تكون بالضرورة حلقة تحتوي مباشرة على عبارة continue. بالإضافة إلى ذلك، كما هو الحال مع الفاصل، لا يُسمح بفواصل الأسطر بين الكلمة الأساسية للمتابعة واسم التصنيف.

بيان العودة

استدعاء الدالة هو تعبير، مثل كل التعبيرات، له قيمة. يتم استخدام عبارة الإرجاع داخل الوظائف لتحديد القيمة التي يتم إرجاعها بواسطة الوظيفة. يمكن أن تظهر عبارة الإرجاع فقط في نص الدالة. وجودها في أي مكان آخر يعتبر خطأ نحوي. عند تنفيذ عبارة الإرجاع، تقوم الدالة بإرجاع قيمة التعبير إلى برنامج الاستدعاء. على سبيل المثال:

إذا كانت الوظيفة لا تحتوي على عبارة إرجاع، فعند استدعائها، سيقوم المترجم بتنفيذ العبارات الموجودة في نص الوظيفة واحدة تلو الأخرى حتى تصل إلى نهاية الوظيفة، ثم يعيد التحكم إلى البرنامج الذي استدعاه. في هذه الحالة، سيعود تعبير الاستدعاء غير محدد. بيان العودة في كثير من الأحيان التعليمات الأخيرةفي الوظيفة، ولكن هذا أمر اختياري تمامًا: ستعيد الوظيفة التحكم إلى برنامج الاستدعاء بمجرد الوصول إلى عبارة الإرجاع، حتى لو كانت متبوعة بعبارات أخرى في نص الوظيفة.

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

الدالة myFun(arr) ( // إذا كان المصفوفة تحتوي على أرقام سالبة، قم بإحباط الدالة for (var i = 0; i

رمي البيان

الاستثناء هو إشارة تشير إلى حدوث موقف استثنائي أو خطأ ما. رمي استثناءهي وسيلة للإشارة إلى مثل هذا الخطأ أو الاستثناء. للقبض على استثناء يعني معالجته، أي. اتخاذ الإجراءات اللازمة أو المناسبة للتعافي من الاستثناء.

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

يحتوي بيان الرمي على بناء الجملة التالي:

رمي التعبير؛

يمكن أن تكون نتيجة التعبير قيمة من أي نوع. يمكن تمرير عبارة الرمي رقمًا يمثل رمز خطأ أو سلسلة تحتوي على نص رسالة الخطأ. يطرح مترجم JavaScript استثناءات باستخدام مثيل لفئة الخطأ لإحدى فئاته الفرعية، ويمكنك استخدام أسلوب مماثل. كائن الخطأ لديه خاصية اسموالذي يحدد نوع الخطأ وخاصيته رسالة، تحتوي على السلسلة التي تم تمريرها إلى وظيفة المنشئ. ما يلي هو مثال لدالة تقوم بتشغيل كائن Error عند استدعائها باستخدام وسيطة غير صالحة:

// دالة مضروب الرقم function Factorial(number) ( // إذا لم تكن وسيطة الإدخال قيمة صالحة، فسيتم طرح استثناء! if (number 1; i *= number, number--); /* جسم حلقة فارغ */ return i ; ) console.log("5! = ",factorial(5)); console.log("-3! = ", Factorial(-3));

عند ظهور استثناء، يقوم مترجم JavaScript بمقاطعة التنفيذ العادي للبرنامج على الفور وينتقل إلى أقرب معالج استثناء. تستخدم معالجات الاستثناء عبارة حاول/قبض/أخيرًا، الموضحة في القسم التالي.

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

إذا تم طرح استثناء في دالة لا تحتوي على بنية محاولة/التقاط/أخيرًا للتعامل معها، فسينتشر الاستثناء إلى الكود الذي يسمى الدالة. بهذه الطريقة، يتم نشر الاستثناءات من خلال البنية المعجمية لطرق JavaScript في مكدس الاستدعاءات. إذا لم يتم العثور على معالج الاستثناء مطلقًا، فسيتم التعامل مع الاستثناء كخطأ وإبلاغ المستخدم به.

حاول/قبض/أخيرًا قم بالإنشاء

تنفذ عملية المحاولة/التقاط/الأخيرة آلية معالجة الاستثناءات في JavaScript. تحدد عبارة المحاولة في هذه البنية ببساطة كتلة من التعليمات البرمجية يتم من خلالها معالجة الاستثناءات. كتلة المحاولة متبوعة ببيان الالتقاط مع كتلة من العبارات التي يتم استدعاؤها في حالة حدوث استثناء في أي مكان في كتلة المحاولة. يتبع عبارة الالتقاط كتلة أخيرًا، والتي تحتوي على الكود النهائي المضمون للتشغيل بغض النظر عما يحدث في كتلة المحاولة.

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

يوضح المقتطف التالي بناء الجملة والغرض من بناء المحاولة/التقاط/الأخير:

حاول ( // تعمل هذه التعليمات البرمجية عادةً بسلاسة من البداية إلى النهاية. // ولكن في مرحلة ما قد تطرح استثناءً // إما مباشرةً باستخدام عبارة الرمي، أو بشكل غير مباشر // عن طريق استدعاء طريقة تطرح الاستثناء. ) ex) ( // يتم تنفيذ العبارات الموجودة في هذه الكتلة في حالة حدوث استثناء // في كتلة المحاولة فقط. يمكن لهذه العبارات استخدام المتغير المحلي ex، والذي يشير // إلى كائن خطأ أو قيمة أخرى محددة في الرمي عبارة. // يمكن لهذه الكتلة إما معالجة الاستثناء بطريقة ما، أو تجاهله أثناء القيام بشيء آخر، أو إعادة طرح الاستثناء // باستخدام عبارة رمي. ) أخيرًا ( // تحتوي هذه الكتلة على بيانات يتم تنفيذها دائمًا بغض النظر عن ما حدث في كتلة المحاولة، يتم تنفيذها إذا اكتملت كتلة المحاولة: // 1) كالمعتاد، بعد الوصول إلى نهاية الكتلة // 2) بسبب فاصل أو متابعة أو بيان إرجاع / / 3) مع الاستثناء الذي تتم معالجته بواسطة كتلة الالتقاط أعلاه // 4) مع استثناء لم يتم اكتشافه ويستمر في الانتشار // إلى مستويات أعلى)

لاحظ أن الكلمة الأساسية الصيد متبوعة بمعرف بين قوسين. يشبه هذا المعرف معلمة دالة. عند اكتشاف استثناء، سيتم تعيين هذه المعلمة إلى الاستثناء (على سبيل المثال، كائن خطأ). على عكس المتغير العادي، فإن المعرف المرتبط ببيان الالتقاط موجود فقط في نص كتلة الالتقاط.

ما يلي هو مثال أكثر واقعية لبناء المحاولة/الالتقاط. يستدعي طريقة العامل () المحددة في المثال السابق وطرق العميل JavaScript () والتنبيه () لتنظيم الإدخال والإخراج:

حاول ( // مطالبة المستخدم بإدخال رقم var n = Number(prompt("أدخل رقمًا موجبًا"، "")); // احسب مضروب الرقم، بافتراض // أن الإدخال صحيح var f = مضروب (n)؛ // اطبع النتيجة تنبيه (n + "! = " + f)؛ ) قبض (على سبيل المثال) ( // إذا كانت البيانات غير صحيحة، فسيتم نقل التحكم هنا تنبيه (على سبيل المثال)؛ // أبلغ المستخدم عن الخطأ)

إذا أدخل المستخدم رقمًا سالبًا، تظهر رسالة تحذير:

هذا مثال على بناء المحاولة/الالتقاط بدون عبارة أخيرًا. على الرغم من أن أخيرًا لا يتم استخدامه كثيرًا مثل الصيد، إلا أنه لا يزال مفيدًا في بعض الأحيان. الكتلة النهائية مضمونة للتنفيذ إذا تم تنفيذ جزء على الأقل من كتلة المحاولة، بغض النظر عن كيفية إكمال التعليمات البرمجية الموجودة في كتلة المحاولة للتنفيذ. تُستخدم هذه الميزة عادةً لتنفيذ العمليات النهائية بعد تنفيذ التعليمات البرمجية في استمرار المحاولة.

في الوضع الطبيعي، يصل التحكم إلى نهاية كتلة المحاولة ثم ينتقل إلى الكتلة الأخيرة، التي تقوم بتنفيذ العمليات النهائية اللازمة. إذا خرج عنصر التحكم من كتلة المحاولة نتيجة لبيان العودة أو المتابعة أو الكسر، فسيتم تنفيذ الكتلة الأخيرة قبل نقل التحكم إلى مكان آخر.

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

إذا كانت الكتلة النهائية نفسها تنقل التحكم باستخدام عبارة إرجاع أو متابعة أو كسر أو رمي أو عن طريق استدعاء طريقة تطرح استثناءً، فسيتم إلغاء أمر النقل المعلق وتنفيذ أمر جديد. على سبيل المثال، إذا قامت كتلة أخيرًا بطرح استثناء، فسيحل هذا الاستثناء محل أي استثناء تم طرحه مسبقًا.

ينهي بيان الإرجاع تنفيذ الوظيفة الحالية ويعيد قيمتها.

يتم تخزين الكود المصدري لهذا المثال التفاعلي في مستودع على GitHub. إذا كنت ترغب في المساهمة في مشروع الأمثلة التفاعلية، يرجى استنساخ https://github.com/mdn/interactive-examples

إرجاع بناء الجملة [[تعبير]]؛ التعبير هو التعبير الذي سيتم إرجاع قيمته. إذا لم يتم تحديده، فسيتم إرجاع غير محدد بدلاً من ذلك. وصف

عندما يتم استدعاء عبارة الإرجاع في دالة، يتوقف تنفيذها. يتم إرجاع القيمة المحددة إلى الموقع الذي تم استدعاء الوظيفة فيه. على سبيل المثال، تقوم الدالة أدناه بإرجاع القيمة التربيعية للوسيطة الخاصة بها، x (حيث x عبارة عن رقم):

الدالة Square(x) ( return x * x; ) var demo = Square(3); // القيمة التجريبية ستكون 9

إذا لم يتم تحديد قيمة الإرجاع، فسيتم إرجاع قيمة غير محددة بدلاً من ذلك.

تقاطع التعبيرات التالية دائمًا تنفيذ الوظيفة:

يعود؛ عودة صحيحة؛ عودة كاذبة؛ العودة س؛ العودة س + ص / 3؛

وظيفة وضع الفواصل المنقوطة تلقائيًا magic(x) ( وظيفة الإرجاع calc(x) ( return x * 42 ); ) var Answer = magic(); الجواب(1337); // 56154 المواصفات تعليق حالة المواصفات
ECMAScript الإصدار الأول (ECMA-262) معيار التعريف الأولي
إيكماسكريبت 5.1 (ECMA-262)
معيار
ECMAScript 2015 (الإصدار السادس، ECMA-262)
تعريف "بيان الإرجاع" في هذه المواصفات.
معيار
أحدث مسودة ECMAScript (ECMA-262)
تعريف "بيان الإرجاع" في هذه المواصفات.
مسودة
التوافق المتصفح

يتم إنشاء جدول التوافق الموجود في هذه الصفحة من البيانات المنظمة. إذا كنت ترغب في المساهمة في البيانات، فيرجى الحصول عليها من المستودع https://github.com/mdn/browser-compat-data وأرسل إلينا طلب سحب لتغييراتك.

تحديث بيانات التوافق على GitHub

أجهزة الكمبيوتر المحمول الخادم Chrome Edge Firefox Internet Explorer Opera Safari Android webview Chrome لنظام Android Firefox لنظام Android Opera لنظام Android Safari على iOS Samsung Internet Node.jsيعود
كروم دعم كامل 1 دعم الحافة الكاملة 12فايرفوكس الدعم الكامل 1أي الدعم الكامل 3أوبرا الدعم الكامل نعمدعم سفاري الكامل نعمWebView Android الدعم الكامل 1كروم أندرويد الدعم الكامل 18دعم فايرفوكس أندرويد الكامل 4دعم Opera Android الكامل نعمدعم Safari iOS الكامل نعمسامسونج إنترنت أندرويد الدعم الكامل 1.0دعم كامل لـnodejs نعم

تعد الوظائف واحدة من أهم العناصر الأساسية للتعليمات البرمجية في JavaScript.

تتكون الوظائف من مجموعة من الأوامر وعادة ما تؤدي مهمة واحدة محددة (على سبيل المثال، جمع الأرقام، وحساب الجذور، وما إلى ذلك).

لن يتم تنفيذ التعليمات البرمجية الموضوعة في دالة إلا بعد استدعاء صريح لهذه الوظيفة.

إعلان الوظيفة

1. بناء الجملة:

// إعلان الوظيفة functionFunctionname(ln1, ln2)( رمز الوظيفة) // استدعاء الوظيفةFunctionname(ln1,lr2);

2. بناء الجملة:

// إعلان الوظيفة var function name=function(ln1, ln2)(رمز الوظيفة) // استدعاء اسم الوظيفة(ln1,lr2);

يحدد functionname اسم الوظيفة. يجب أن يكون لكل وظيفة في الصفحة اسم فريد. يجب تحديد اسم الوظيفة بأحرف لاتينيةويجب ألا يبدأ بالأرقام.

ln1 وln2 متغيرات أو قيم يمكن تمريرها إلى الوظيفة. يمكن تمرير عدد غير محدود من المتغيرات لكل دالة.

يرجى ملاحظة: حتى لو لم يتم تمرير أي متغيرات إلى الدالة، فلا تنس إدخال الأقواس "()" بعد اسم الدالة.

يرجى ملاحظة أن أسماء الوظائف في JavaScript حساسة لحالة الأحرف.

مثال على وظيفة جافا سكريبت

لن يتم تنفيذ وظيفة messageWrite() في المثال أدناه إلا بعد النقر فوق الزر.

لاحظ أن هذا المثال يستخدم حدث onclick. سيتم تغطية أحداث JavaScript بالتفصيل لاحقًا في هذا البرنامج التعليمي.

// تقوم الوظيفة بكتابة نص إلى الصفحة function messageWrite() ( document.write("تمت كتابة هذا النص إلى الصفحة باستخدام JavaScript!"); )

تمرير المتغيرات إلى الوظائف

يمكنك تمرير عدد غير محدود من المتغيرات إلى الوظائف.

يرجى ملاحظة: جميع عمليات التلاعب بالمتغيرات داخل الوظائف لا يتم تنفيذها فعليًا على المتغيرات نفسها، ولكن على نسختها، وبالتالي فإن محتويات المتغيرات نفسها لا تتغير نتيجة لتنفيذ الوظائف.

/* لنحدد دالة تضيف 10 إلى المتغير الذي تم تمريره وتعرض النتيجة على الصفحة */ function plus(a)( a=a+10; document.write("إخراج الدالة: " + a+"
"); ) var a=25; document.write("قيمة المتغير قبل استدعاء الدالة: "+a+"
"); // استدعاء الدالة عن طريق تمرير المتغير a plus(a); document.write("قيمة المتغير بعد استدعاء الدالة: "+a+"
");

نظرة سريعة

للوصول إلى متغير عام من دالة بدلاً من نسخة منها، استخدم window.variable_name.

الدالة plus(a)( window.a=a+10; ) var a=25; document.write("قيمة المتغير قبل استدعاء الدالة:"+a+"
"); plus(a); document.write("قيمة المتغير بعد استدعاء الدالة: "+a+"
");

نظرة سريعة

أمر العودة

باستخدام أمر الإرجاع، يمكنك إرجاع القيم من الوظائف.

// ترجع الدالة المجموع مجموع المتغيرات التي تم تمريرها إليها function sum(v1,v2)( return v1+v2; ) document.write("5+6=" + sum(5,6) + "
"); document.write("10+4=" + مجموع(10,4) + "
");

نظرة سريعة

وظائف مدمجة

بالإضافة إلى الوظائف المحددة من قبل المستخدم، تحتوي JavaScript أيضًا على وظائف مدمجة.

على سبيل المثال، تتيح لك وظيفة isFinite المضمنة التحقق مما إذا كانت القيمة التي تم تمريرها رقمًا صالحًا.

Document.write(isFinite(40)+"
"); document.write(isFinite(-590)+"
"); document.write(isFinite(90.33)+"
"); document.write(isFinite(NaN)+"
"); document.write(isFinite("هذه سلسلة")+"
");

نظرة سريعة

ملحوظة: القائمة الكاملةيمكنك العثور على وظائف JavaScript المضمنة في .

المتغيرات المحلية والعالمية

تسمى المتغيرات التي تم إنشاؤها داخل الوظائف بالمتغيرات المحلية. يمكنك الوصول إلى هذه المتغيرات فقط ضمن الوظائف التي تم تعريفها فيها.

بعد اكتمال تنفيذ كود الدالة، يتم تدمير هذه المتغيرات. وهذا يعني أنه يمكن تعريف المتغيرات التي لها نفس الاسم في وظائف مختلفة.

تسمى المتغيرات التي يتم إنشاؤها خارج كود الوظيفة بالمتغيرات العامة، ويمكن الوصول إلى هذه المتغيرات من أي مكان في الكود.

إذا قمت بتعريف متغير بدون var داخل دالة، فإنه يصبح عالميًا أيضًا.

يتم تدمير المتغيرات العامة فقط بعد إغلاق الصفحة.

// قم بتعريف المتغيرات العامة var1 وvar2 var var1="var1 موجود"; فار var2؛ function func1() ( // قم بتعيين قيمة var2 داخل الوظيفة func1 var var2="var2 موجود"; ) // من دالة أخرى، قم بإخراج محتويات المتغير var1 وvar2 إلى وظيفة الصفحة func2() ( // الإخراج محتويات المتغير var1 document.write( var1 + "
"); // إخراج محتويات المتغير var2 document.write(var2); )

نظرة سريعة

لاحظ أنه عند الطباعة على الشاشة، سيكون لـ var2 قيمة فارغة لأن func1 يعمل على "الإصدار" المحلي من var2.

استخدام وظائف مجهولة

الوظائف التي لا تحتوي على اسم عند الإعلان عنها تسمى مجهولة.

يتم الإعلان بشكل أساسي عن عدم استدعاء الوظائف المجهولة من التعليمات البرمجية مثل الوظائف العادية، ولكن سيتم تمريرها إلى وظائف أخرى كمعلمة.

الدالة arrMap(arr,func)( var res=new Array; for (var i=0;i


قمة