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

💖 هل يعجبك؟شارك الرابط مع أصدقائك

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

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

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

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

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

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

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

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

من خلال تعيين اسم للحلقة، يمكن بعد ذلك استخدامه في عبارات Break and continue، أو داخل الحلقة للخروج منها، أو للانتقال إلى بداية الحلقة، إلى التكرار التالي. إن عبارات الاستراحة والمتابعة هي عبارات 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 مباشرة إلى حالتها، و لحلقةيقوم أولاً بتقييم تعبير الزيادة ثم يعود إلى الشرط. يوضح المثال التالي استخدام عبارة continue بدون تسمية للخروج من تكرار الحلقة الحالية للأرقام الزوجية:

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

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

بيان العودة

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

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

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

الدالة 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. تحدد عبارة المحاولة في هذه البنية ببساطة كتلة من التعليمات البرمجية يتم من خلالها معالجة الاستثناءات. كتلة المحاولة متبوعة ببيان الالتقاط مع كتلة من العبارات التي يتم استدعاؤها في حالة حدوث استثناء في أي مكان في كتلة المحاولة. يتبع عبارة الالتقاط كتلة أخيرًا، والتي تحتوي على الكود النهائي المضمون للتشغيل بغض النظر عما يحدث في كتلة المحاولة.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

يرجى ملاحظة أن هذا المثال يستخدم حدث onclick. أحداث جافا سكريبتسيتم مناقشتها بالتفصيل لاحقًا في هذا الكتاب المدرسي.

// تقوم الوظيفة بكتابة نص إلى الصفحة 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 target) return null; else return find(start + 5, "(" + History + " + 5)") || find (start * 3, "(" + History + " * 3)" ) return find(1, "1"); ) console.log(findSolution(24)); // → (((1 * 3) + 5) * 3)

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

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

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

لفهم كيفية تحقيق الدالة للتأثير المطلوب بشكل أفضل، دعونا نلقي نظرة على الاستدعاءات التي تجريها لإيجاد حل للرقم 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، التي تُرجع أصغر وسيطاتها. الآن يمكننا كتابة مثل هذه الوظيفة بأنفسنا. اكتب دالة 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، مما يعني أن الحرف الأخير سيكون له موضع السلسلة. الطول - 1. وبعبارة أخرى، سلسلة من حرفين لها طول 2، ومواضع الأحرف الخاصة بها ستكون 0 و1.

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

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



أخبر الأصدقاء