دليل جافا سكريبت الجزء 4: الميزات

ننشر اليوم الجزء الرابع من ترجمة دليل جافا سكريبت المخصص للوظائف.

الجزء الأول: البرنامج الأول وميزات اللغة والمعايير
الجزء الثاني: نمط الكود وهيكل البرنامج
الجزء الثالث: المتغيرات وأنواع البيانات والتعبيرات والكائنات
الجزء 4: الميزات
الجزء الخامس: المصفوفات والحلقات
الجزء السادس: الاستثناءات ، الفاصلة المنقوطة ، حرفية أحرف البدل
الجزء 7: الوضع الصارم ، هذه الكلمة الرئيسية ، والأحداث ، والوحدات ، والحسابات الرياضية
الجزء الثامن: نظرة عامة على ميزات ES6
الجزء التاسع: نظرة عامة على معايير ES7 و ES8 و ES9



وظائف JavaScript


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

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

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

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

أولاً ، نعتبر ميزات العمل مع الوظائف والبنى النحوية المقابلة التي كانت موجودة في اللغة قبل ظهور معيار ES6 ولا تزال ذات صلة.

هذا هو شكل إعلان الوظيفة.

 function doSomething(foo) { // - } 

في هذه الأيام ، تسمى هذه الدالات "عادية" ، وتميزها عن دالات "السهم" التي ظهرت في ES6.

يمكنك تعيين دالة لمتغير أو ثابت. يسمى هذا البناء تعبير دالة.

 const doSomething = function(foo) { // - } 

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

 const doSomething = function doSomFn(foo) { // - } 

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

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

 const doSomething = foo => { // - } 

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

معلمات الوظيفة


المعلمات هي متغيرات يتم تعيينها في مرحلة التصريح عن دالة وستحتوي على القيم التي تم تمريرها إليها (تسمى هذه القيم وسيطات). قد لا تحتوي الدوال في JavaScript على أية معلمات أو تحتوي على معلمة واحدة أو أكثر.

 const doSomething = () => { // - } const doSomethingElse = foo => { // - } const doSomethingElseAgain = (foo, bar) => { // - } 

فيما يلي بعض الأمثلة على وظائف الأسهم.

بدءًا بمعيار ES6 ، يمكن أن تحتوي الوظائف على ما يسمى "المعلمات الافتراضية".

 const doSomething = (foo = 1, bar = 'hey') => { // - } 

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

 doSomething(3) doSomething() 

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

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

 const doSomething = (foo = 1, bar = 'hey') => { // - } const args = [2, 'ho!'] doSomething(...args) 

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

 const doSomething = ({ foo = 1, bar = 'hey' }) => { // - console.log(foo) // 2 console.log(bar) // 'ho!' } const args = { foo: 2, bar: 'ho!' } doSomething(args) 

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

تم إرجاع القيم من الوظائف


تُرجع جميع الدالات قيمة معينة. إذا لم يتم تحديد أمر الإرجاع بشكل صريح ، فسوف تُرجع الدالة undefined .

 const doSomething = (foo = 1, bar = 'hey') => { // - } console.log(doSomething()) 

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

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

 const doSomething = () => { return 'test' } const result = doSomething() // result === 'test' 

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

 const doSomething = () => { return ['Roger', 6] } const [ name, age ] = doSomething() console.log(name, age) //Roger 6 

يمكن قراءة ثوابت البناء const [ name, age ] = doSomething() على النحو التالي: "قم بتعريف name وثوابت age وتعيين قيم عناصر المصفوفة التي سترجعها الدالة."
إليك كيف يبدو الشيء نفسه باستخدام كائن.

 const doSomething = () => { return {name: 'Roger', age: 6} } const { name, age } = doSomething() console.log(name, age) //Roger 6 

دالات متداخلة


يمكن الإعلان عن الوظائف داخل الوظائف الأخرى.

 const doSomething = () => { const doSomethingElse = () => {} doSomethingElse() return 'test' } doSomething() 

يقتصر نطاق دالة متداخلة على وظيفة خارجية لها ؛ لا يمكن استدعاؤها من الخارج.

طرق الكائن


عندما يتم استخدام الدالات كخصائص للكائنات ، تسمى هذه الدوال أساليب الكائن.

 const car = { brand: 'Ford', model: 'Fiesta', start: function() {   console.log(`Started`) } } car.start() 

هذه الكلمة


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

 const car = { brand: 'Ford', model: 'Fiesta', start: function() {   console.log(`Started ${this.brand} ${this.model}`) }, stop: () => {   console.log(`Stopped ${this.brand} ${this.model}`) } } car.start() //Started Ford Fiesta car.stop() //Stopped undefined undefined 

كما ترى ، يؤدي استدعاء طريقة start() إلى النتيجة المتوقعة ، ولكن من الواضح أن طريقة stop() لا تعمل بشكل صحيح.

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

إليك كيفية ظهور تنفيذ هذا الرمز في وحدة تحكم المتصفح.

 const test = { fn: function() {   console.log(this) }, arrFn: () => {   console.log(this) } } test.fn() test.arrFn() 


ميزات هذه الكلمة الرئيسية في الوظائف التقليدية والسهم

كما ترى ، فإن استدعاء هذا في وظيفة عادية يعني استدعاء الكائن ، this في وظيفة السهم يشير إلى window .

كل هذا يعني أن وظائف السهم ليست مناسبة لدور الكائن والمنشئ (إذا حاولت استخدام وظيفة السهم TypeError فسيتم TypeError ).

يتم استدعاء التعبيرات الوظيفية فورًا


التعبير عن الوظيفة التي يتم استدعاؤها على الفور (IIFE) هي وظيفة يتم استدعاؤها تلقائيًا فور الإعلان عنها.

 ;(function () { console.log('executed') })() 

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

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

 const something = (function () { return 'IIFE' })() console.log(something) 

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

ترقية الميزة


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

 doSomething() //did something function doSomething() { console.log('did something') } 

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

إذا تم استخدام تعبير وظيفي في حالة مماثلة ، فسيؤدي رمز مشابه إلى ظهور خطأ.

 doSomething() //TypeError var doSomething = function () { console.log('did something') } 

في هذه الحالة ، اتضح أنه على الرغم من أن إعلان متغير doSomething يرتفع إلى أعلى النطاق ، فإن هذا لا ينطبق على عملية التعيين.
إذا كنت تستخدم بدلاً من var كلمات أساسية let أو const في وضع مشابه ، فلن يعمل هذا الرمز أيضًا ، ومع ذلك ، سيعرض النظام رسالة خطأ مختلفة ( ReferenceError بدلاً من TypeError ) ، لأنه عند استخدام let و const ، لا يتم رفع الإعلانات المتغيرة والثابتة.

وظائف السهم


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

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

 const myFunction = function () { //... } 

فيما يلي الإعلان عن وظيفة السهم ، والتي ، بشكل عام ، إذا لم تأخذ في الاعتبار ميزات وظائف السهم ، فهي مشابهة للوظيفة السابقة.

 const myFunction = () => { //... } 

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

 const myFunction = (a,b) => a + b console.log(myFunction(1,2)) //3 

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

 const myFunction = a => a / 2 console.log(myFunction(8)) //4 

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

return العودة الضمنية لنتائج الوظيفة


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

 const myFunction = () => ({value: 'test'}) const obj = myFunction() console.log(obj.value) //test 

word الكلمات الرئيسية هذا ووظائف السهم


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

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

في حالة وظائف السهم ، اتضح أن this الربط لا يتم تنفيذها فيها ؛ فهم يستخدمون this من نطاقهم. ونتيجة لذلك ، لا يوصى باستخدامها كطرق للكائنات.

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

 <!DOCTYPE html> <html> <body>   <button id="fn">Function</button>   <button id="arrowFn">Arrow function</button>   <script>     const f = document.getElementById("fn")     f.addEventListener('click', function () {         alert(this === f)     })     const af = document.getElementById("arrowFn")     af.addEventListener('click', () => {         alert(this === window)     })   </script> </body> </html> 

في هذه الحالة ، عند النقر فوق هذه الأزرار ، ستظهر النوافذ التي تحتوي على true . ومع ذلك ، في معالج حدث click للزر ذي المعرف fn ، يتم التحقق من مساواة this الزر ، وفي الزر مع arrowFn المعرف ، window التحقق من مساواة this وكائن window .

ونتيجة لذلك ، إذا كنت بحاجة إلى استدعاء this في معالج الأحداث لعنصر HTML ، فلن تعمل وظيفة السهم لتصميم مثل هذا المعالج.

دوائر قصيرة


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

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

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

 const bark = dog => { const say = `${dog} barked!` ;(() => console.log(say))() } bark(`Roger`) // Roger barked! 

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

 const prepareBark = dog => { const say = `${dog} barked!` return () => console.log(say) } const bark = prepareBark(`Roger`) bark() // Roger barked! 

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

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

 const prepareBark = dog => { const say = `${dog} barked!` return () => {   console.log(say) } } const rogerBark = prepareBark(`Roger`) const sydBark = prepareBark(`Syd`) rogerBark() sydBark() 

سيخرج هذا الرمز ما يلي.

 Roger barked! Syd barked! 

اتضح أن قيمة ثابت say مرتبطة بالدالة التي يتم إرجاعها من prepareBark() .

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

الملخص


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

أعزائي القراء! ما هو شعورك حول وظائف السهم في جافا سكريبت؟

Source: https://habr.com/ru/post/ar430382/


All Articles