ننشر اليوم الجزء الرابع من ترجمة دليل جافا سكريبت المخصص للوظائف.
→
الجزء الأول: البرنامج الأول وميزات اللغة والمعايير→
الجزء الثاني: نمط الكود وهيكل البرنامج→
الجزء الثالث: المتغيرات وأنواع البيانات والتعبيرات والكائنات→
الجزء 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 = () => {
فيما يلي بعض الأمثلة على وظائف الأسهم.
بدءًا بمعيار ES6 ، يمكن أن تحتوي الوظائف على ما يسمى "المعلمات الافتراضية".
const doSomething = (foo = 1, bar = 'hey') => {
وهي تمثل القيم القياسية التي يتم تعيينها بواسطة معلمات الدوال إذا لم يتم تعيين قيم بعض المعلمات عند استدعائها. على سبيل المثال ، يمكن استدعاء الوظيفة الموضحة أعلاه عن طريق تمريرها إلى جميع المعلمتين التي تتلقاها وطرق أخرى.
doSomething(3) doSomething()
في ES8 ، أصبح من الممكن وضع فاصلة بعد الوسيطة الأخيرة للدالة (يسمى هذا بفاصلة زائدة). تتيح لك هذه الميزة زيادة راحة تحرير التعليمات البرمجية عند استخدام أنظمة التحكم في الإصدار أثناء تطوير البرنامج. يمكن العثور على تفاصيل حول هذا
هنا وهنا .
يمكن تمثيل الوسيطات التي تم تمريرها إلى الدوال كصفائف. من أجل تحليل هذه الحجج ، يمكنك استخدام عامل يشبه ثلاث نقاط (وهذا هو ما يسمى "عامل التمديد" أو "عامل الانتشار"). إليك كيف تبدو.
const doSomething = (foo = 1, bar = 'hey') => {
إذا احتاجت الدوال إلى أخذ العديد من المعلمات ، فقد يكون من الصعب تذكر ترتيب تسلسلها. في مثل هذه الحالات ، يتم استخدام كائنات ذات معلمات وفرص لتدمير كائنات ES6.
const doSomething = ({ foo = 1, bar = 'hey' }) => {
تسمح هذه التقنية ، لوصف المعلمات في شكل خصائص الكائن وتمرير الوظيفة إلى الكائن ، بالوصول إلى الوظيفة للوصول إلى المعلمات بأسمائها دون استخدام تركيبات إضافية. اقرأ المزيد عن هذه التقنية
هنا .
تم إرجاع القيم من الوظائف
تُرجع جميع الدالات قيمة معينة. إذا لم يتم تحديد أمر الإرجاع بشكل صريح ، فسوف تُرجع الدالة
undefined
.
const doSomething = (foo = 1, bar = 'hey') => {
ينتهي تنفيذ الوظيفة إما بعد تنفيذ كل التعليمات البرمجية التي تحتوي عليها ، أو بعد مواجهة الكلمة الأساسية المرتجعة في التعليمات البرمجية. عند مصادفة هذه الكلمة الأساسية في إحدى الوظائف ، تكتمل عملياتها ويتم نقل التحكم إلى المكان الذي تم استدعاء الوظيفة منه.
إذا حددت قيمة معينة بعد الكلمة الأساسية
return
، فإن هذه القيمة تعود إلى مكان استدعاء الوظيفة كنتيجة لتنفيذ هذه الوظيفة.
const doSomething = () => { return 'test' } const result = doSomething()
يمكن إرجاع قيمة واحدة فقط من دالة. لكي تتمكن من إرجاع قيم متعددة ، يمكنك إرجاعها إما ككائن باستخدام كائن حرفي أو كصفيف ، وعند استدعاء دالة ، استخدم بنية التخصيص المدمرة. يتم حفظ أسماء المعلمات. في الوقت نفسه ، إذا كنت بحاجة إلى العمل مع كائن أو صفيف تم إرجاعه من دالة ، أي في شكل كائن أو صفيف ، يمكنك الاستغناء عن التخصيص المدمر.
const doSomething = () => { return ['Roger', 6] } const [ name, age ] = doSomething() console.log(name, age)
يمكن قراءة ثوابت البناء
const [ name, age ] = doSomething()
على النحو التالي: "قم بتعريف
name
وثوابت
age
وتعيين قيم عناصر المصفوفة التي سترجعها الدالة."
إليك كيف يبدو الشيء نفسه باستخدام كائن.
const doSomething = () => { return {name: 'Roger', age: 6} } const { name, age } = doSomething() console.log(name, age)
دالات متداخلة
يمكن الإعلان عن الوظائف داخل الوظائف الأخرى.
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()
كما ترى ، يؤدي استدعاء طريقة
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()
إذا قمت بنقل استدعاء دالة بحيث تتم بعد إعلانها ، فلن يتغير شيء.
إذا تم استخدام تعبير وظيفي في حالة مماثلة ، فسيؤدي رمز مشابه إلى ظهور خطأ.
doSomething()
في هذه الحالة ، اتضح أنه على الرغم من أن إعلان متغير
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))
كما ترى ، يتم وصف معلمات دالات الأسهم ، كما هو الحال في الوظائف العادية ، بين قوسين. علاوة على ذلك ، إذا كانت هذه الوظيفة تأخذ معلمة واحدة فقط ، فيمكن تحديدها بدون قوسين. على سبيل المثال ، هنا دالة ترجع نتيجة قسمة الرقم الذي تم تمريره إليها على 2.
const myFunction = a => a / 2 console.log(myFunction(8))
ونتيجة لذلك ، اتضح أن وظائف الأسهم ملائمة جدًا للاستخدام في المواقف التي تتطلب وظائف صغيرة.
return العودة الضمنية لنتائج الوظيفة
لقد تطرقنا بالفعل إلى هذه الميزة من وظائف الأسهم ، ولكن من المهم جدًا مناقشتها بمزيد من التفاصيل. نحن نتحدث عن حقيقة أن وظائف السهم أحادية الخط تدعم العودة الضمنية لنتائج عملهم. مثال على إرجاع قيمة بدائية من دالة سهم أحادية السطر رأيناه بالفعل. ماذا لو أعادت هذه الوظيفة كائنًا؟ في هذه الحالة ، يمكن أن تربك الأقواس المتعرجة للكائن الحرفي النظام ، لذلك يتم استخدام الأقواس في نص الوظيفة.
const myFunction = () => ({value: 'test'}) const obj = myFunction() console.log(obj.value)
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`)
القيمة التي ترجعها هذه الوظيفة لا تهمنا بعد ، يتم عرض النص في وحدة التحكم باستخدام IIFE ، والذي في هذه الحالة لا يلعب دورًا خاصًا ، ومع ذلك ، سيساعدنا هذا على رؤية العلاقة بين هذه الوظيفة ومتغيرها ، حيث ، بدلاً من استدعاء وظيفة تعرض نص إلى وحدة التحكم ، سوف نعيد هذه الوظيفة من
bark()
الدالة المعاد كتابتها
bark()
.
const prepareBark = dog => { const say = `${dog} barked!` return () => console.log(say) } const bark = prepareBark(`Roger`) bark()
نتيجة الكود في حالتين هي نفسها. ولكن في الحالة الثانية ، يتم تخزين ما تم نقله إلى الوظيفة الأصلية عندما كانت تسمى (اسم الكلب ،
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
الكلمة الرئيسية في المواقف المختلفة ، وعن عمليات الإغلاق. في المرة القادمة نناقش المصفوفات والحلقات.
أعزائي القراء! ما هو شعورك حول وظائف السهم في جافا سكريبت؟
