وظائف ترتيب أعلى في جافا سكريبت

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

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



من أجل فهم هذا المفهوم بشكل كامل ، تحتاج أولاً إلى فهم مفهوم البرمجة الوظيفية (البرمجة الوظيفية) وما هي الوظائف من الدرجة الأولى (وظائف الدرجة الأولى).

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

ما هي البرمجة الوظيفية؟


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

من بين اللغات التي تدعم البرمجة الوظيفية هي JavaScript و Haskell و Clojure و Scala و Erlang.

وظائف الدرجة الأولى


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

على وجه الخصوص ، في وظائف JS يتم تمثيلها ككائنات من نوع خاص - هذه كائنات من نوع Function . فكر في مثال:

 function greeting() { console.log('Hello World'); } //   greeting();  //  'Hello World' 

من أجل إثبات أن الوظائف في JavaScript هي كائنات ، يمكننا القيام بما يلي ، مع متابعة المثال السابق:

 //     ,       greeting.lang = 'English'; //  'English' console.log(greeting.lang); 

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

في JavaScript بوظائف ، يمكنك أن تفعل نفس الشيء الذي يمكن القيام به مع كيانات من أنواع أخرى ، مثل Object ، String ، Number . يمكن تمرير الوظائف كمعلمات للوظائف الأخرى. عادة ما تعمل هذه الوظائف ، التي يتم نقلها إلى الآخرين ، كوظائف رد اتصال (رد اتصال). يمكن تعيين الوظائف للمتغيرات وتخزينها في المصفوفات وما إلى ذلك. هذا هو السبب في أن الوظائف في JS هي كائنات من الدرجة الأولى.

تعيين وظائف للمتغيرات والثوابت


يمكن تعيين الوظائف للمتغيرات والثوابت:

 const square = function(x) { return x * x; } //   25 square(5); 

يمكن تعيين الدوال المعينة للمتغيرات أو الثوابت لمتغيرات أو ثوابت أخرى:

 const foo = square; //  36 foo(6); 

تمرير الوظائف كمعلمات


يمكن تمرير الوظائف كمعلمات للوظائف الأخرى:

 function formalGreeting() { console.log("How are you?"); } function casualGreeting() { console.log("What's up?"); } function greet(type, greetFormal, greetCasual) { if(type === 'formal') {   greetFormal(); } else if(type === 'casual') {   greetCasual(); } } //  'What's up?' greet('casual', formalGreeting, casualGreeting); 

الآن بعد أن عرفنا كيف تتصرف وظائف الدرجة الأولى ، دعنا نتحدث عن وظائف الترتيب الأعلى.

وظائف ترتيب أعلى


الدوال ذات الترتيب الأعلى هي الدوال التي تعمل مع الدوال الأخرى ، إما أخذها كمعلمات أو إرجاعها. ببساطة ، تعد دالة الترتيب الأعلى دالة تأخذ دالة كوسيطة أو تُرجع دالة كقيمة إخراج.

على سبيل المثال ، تعد وظائف JavaScript Array.prototype.map Array.prototype.filter و Array.prototype.reduce و Array.prototype.reduce هي وظائف ذات ترتيب أعلى.

وظائف النظام الأعلى في العمل


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

▍ أسلوب Array.prototype.map


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

تأخذ وظيفة رد الاتصال التي تم تمريرها إلى map() ثلاث وسيطات: element (العنصر) index (الفهرس) array (الصفيف). دعونا نلقي نظرة على بعض الأمثلة.

المثال رقم 1


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

حل مشكلة دون استخدام وظائف عالية الترتيب


 const arr1 = [1, 2, 3]; const arr2 = []; for(let i = 0; i < arr1.length; i++) { arr2.push(arr1[i] * 2); } //  [ 2, 4, 6 ] console.log(arr2); 

حل مشكلة باستخدام خريطة وظيفية عالية الترتيب


 const arr1 = [1, 2, 3]; const arr2 = arr1.map(function(item) { return item * 2; }); console.log(arr2); 

يمكنك أيضًا تقليل حجم هذا الرمز إذا كنت تستخدم وظيفة السهم:

 const arr1 = [1, 2, 3]; const arr2 = arr1.map(item => item * 2); console.log(arr2); 

المثال رقم 2


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

حل مشكلة دون استخدام وظائف عالية الترتيب


 const birthYear = [1975, 1997, 2002, 1995, 1985]; const ages = []; for(let i = 0; i < birthYear.length; i++) { let age = 2018 - birthYear[i]; ages.push(age); } //  [ 43, 21, 16, 23, 33 ] console.log(ages); 

حل مشكلة باستخدام خريطة وظيفية عالية الترتيب


 const birthYear = [1975, 1997, 2002, 1995, 1985]; const ages = birthYear.map(year => 2018 - year); //  [ 43, 21, 16, 23, 33 ] console.log(ages); 

▍ طريقة Array.prototype.filter


تنشئ طريقة filter() ، على أساس المصفوفة ، صفيفًا جديدًا تسقط فيه عناصر المصفوفة الأصلية ، وهو ما يتوافق مع الحالة المحددة في دالة رد الاتصال التي يتم تمريرها إلى هذه الطريقة. تأخذ هذه الوظيفة ، كما هو الحال في طريقة map() ، 3 وسيطات: element index array .

ضع في اعتبارك مثالًا تم إنشاؤه بنفس الطريقة عند التفكير في طريقة map() .

مثال


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

حل مشكلة دون استخدام وظائف عالية الترتيب


 const persons = [ { name: 'Peter', age: 16 }, { name: 'Mark', age: 18 }, { name: 'John', age: 27 }, { name: 'Jane', age: 14 }, { name: 'Tony', age: 24}, ]; const fullAge = []; for(let i = 0; i < persons.length; i++) { if(persons[i].age >= 18) {   fullAge.push(persons[i]); } } console.log(fullAge); 

حل مشكلة باستخدام مرشح وظيفة أعلى مرتبة


 const persons = [ { name: 'Peter', age: 16 }, { name: 'Mark', age: 18 }, { name: 'John', age: 27 }, { name: 'Jane', age: 14 }, { name: 'Tony', age: 24}, ]; const fullAge = persons.filter(person => person.age >= 18); console.log(fullAge); 

▍ أسلوب Array.prototype.reduce


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

يقبل رد الاتصال أربع معلمات: accumulator ( currentValue ) ، currentValue (القيمة الحالية) ، currentIndex (الفهرس الحالي) ، sourceArray (صفيف المصدر).

إذا تم initialValue معلمة initialValue ، initialValue في بداية الطريقة مساوياً لهذه القيمة ، وستتم كتابة العنصر الأول للصفيف المعالج إلى currentValue .

إذا لم يتم توفير المعلمة initialValue للطريقة ، فسيتم كتابة العنصر الأول من الصفيف إلى المجمع ، والثاني إلى currentValue .

مثال


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

حل مشكلة دون استخدام وظائف عالية الترتيب


 const arr = [5, 7, 1, 8, 4]; let sum = 0; for(let i = 0; i < arr.length; i++) { sum = sum + arr[i]; } //  25 console.log(sum); 

تقليل حل مشكلة باستخدام دالة ترتيب أعلى


أولاً ، ضع في اعتبارك استخدام طريقة reduce() دون إعطائها قيمة أولية.

 const arr = [5, 7, 1, 8, 4]; const sum = arr.reduce(function(accumulator, currentValue) { return accumulator + currentValue; }); //  25 console.log(sum); 

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

الآن دعونا نلقي نظرة على كيف سيبدو حل المشكلة إذا قمنا بتمرير القيمة الأولية لأسلوب reduce() .

 const arr = [5, 7, 1, 8, 4]; const sum = arr.reduce(function(accumulator, currentValue) { return accumulator + currentValue; }, 10); //  35 console.log(sum); 

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

إنشاء وظائف مخصصة عالية الترتيب


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

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

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

 const strArray = ['JavaScript', 'Python', 'PHP', 'Java', 'C']; function mapForEach(arr, fn) { const newArray = []; for(let i = 0; i < arr.length; i++) {   newArray.push(     fn(arr[i])   ); } return newArray; } const lenArray = mapForEach(strArray, function(item) { return item.length; }); //  [ 10, 6, 3, 4, 1 ] console.log(lenArray); 

في هذا المثال ، أنشأنا mapForEach لوظيفة أعلى mapForEach ، والتي تأخذ مصفوفة ووظيفة رد اتصال fn . تعمل الدالة mapForEach المصفوفة في حلقة mapForEach رد الاتصال fn في كل تكرار لهذه الحلقة.

يقبل رد fn عنصر السلسلة الحالي للصفيف ويعيد طول هذا العنصر. يتم استخدام ما تقوم بإرجاع الدالة fn في الأمر newArray.push() في الصفيف الذي mapForEach() . ستتم كتابة هذا الصفيف في النهاية إلى ثابت lenArray .

الملخص


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

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

أعزائي القراء! هل يجب عليك كتابة وظائف الترتيب العالي الخاصة بك؟

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


All Articles