الدوال العادية
مفهوم الدوال
الدالة (Function) عبارة عن مجموعة أوامر مجمعة في مكان واحد و تتنفذ عندما يتم استدعائها.
جافاسكربت تحتوي على مجموعة كبيرة جداً من الدوال الجاهزة و التي سبق أن إستخدامنا بعضها مثل الدوال
في هذا الدرس ستتعلم جميع الطرق و الأساليب التي يمكنك من خلالها إنشاء دوال جديدة و التعامل معها.
الدوال الجاهزة في جافاسكربت يقال لها Built-in Functions.
الدوال التي يقوم المبرمج بتعريفها يقال لها User-defined Functions.
تعريف دوال جديدة
الشكل الأساسي الذي يجب إتباعه عند تعريف أي دالة في جافاسكربت هو التالي:
// statements
}
- function: نستخدمها لتعريف دالة جديدة.
- name: مكانها نضع الإسم الذي نريد إعطاؤه للدالة، و الذي من خلاله يمكننا استدعاءها.
- parameters: هنا يمكنك وضع متغيرات، هذه المتغيرات تمرر لها قيم عند استدعاء الدالة.
- statements: تعني الأوامر التي سنضعها في الدالة و التي ستتنفذ عند إستدعائها.
تعريف الدالة يقصد به تعريف ما تقوم به الدالة حين يتم إستدعاءها.
إذاً بعد تعريف الدالة يمكن استدعاءها حتى يتم تنفيذ الأوامر الموجودة فيها.
في المثال التالي قمنا بتعريف دالة إسمها
المثال الأول
<!DOCTYPE html>
<html>
<body>
<script>
// demo هنا قمنا بتعريف دالة إسمها
function demo() {
document.write('My first function is called');
}
// حتى يتم تنفيذ الأمر الموضوع فيها demo هنا قمنا باستدعاء الدالة
demo();
</script>
</body>
</html>
هنا قمنا بتعريف دالة إسمها
المثال الثاني
<!DOCTYPE html>
<html>
<body>
<script>
// عند إستدعائها نمرر لها إسم, فتطبع جملة ترحيب بإسم الشخص الذي نمرره لها greeting هنا قمنا بتعريف دالة إسمها
function greeting(name) {
document.write('Hello ' + name + ' welcome to our company.');
}
// user هنا قمنا بتخزين إسم الشخص الذي سنمرره للدالة في المتغير
let user = 'Ahmed';
// حتى تطبع رسالة ترحيب له user و تمرير إسم الشخص الذي قمنا بتخزينه في المتغير greeting() هنا قمنا باستدعاء الدالة
greeting(user);
</script>
</body>
</html>
المتغير الذي يتم تعريفه بين أقواس الدالة يسمى باراميتر ( Parameter ).
الباراميتر يُعتبر متغيّر محلّي ( Local Variable ) بالنسبة للدالة حيث أنه لا يمكن الوصول إليه من خارجها.
في المثال التالي قمنا بتعريف دالة إسمها
المثال الثالث
<!DOCTYPE html>
<html>
<body>
<script>
// عند إستدعائها نمرر لها عددين فتقوم بإرجاع ناتج جمعهما get_sum هنا قمنا بتعريف دالة إسمها
function getSum(a, b) {
return a + b;
}
// x في المتغير getSum() هنا قمنا بتخزين ناتج العددين 3 و 5 الذي سترجعه الدالة
x = getSum(3, 5);
// و التي ستساوي 8 x هنا قمنا بعرض قيمة المتغير
document.write('x = ' + x);
</script>
</body>
</html>
إذاً في جافاسكربت نستخدم الكلمة
وضع قيم إفتراضية للباراميترات
جافاسكربت تتيح لك وضع قيم إفتراضية للباراميترات ليتم استخدامها بشكل تلقائي في حال تم استدعاء الدالة و لم يتم تمرير قيم للباراميترات الموضوعة فيها.
القيمة الإفتراضية التي يتم وضعها للباراميتر يقال لها Default Value أو Default Argument.
في المثال التالي قمنا بتعريف دالة إسمها
- الباراميتر الأول إسمه
name و لا يملك قيمة إفتراضية. - الباراميتر الثاني إسمه
language و يملك النص'English' كقيمة إفتراضية.
كل ما تفعله هذه الدالة عند إستدعائها هو طباعة رسالة ترحيب للمستخدم باللغة التي يتم تحديدها لها. و بما أن الباراميتر
مثال
<!DOCTYPE html>
<html>
<body>
<script>
// حتى تطبع رسالة ترحيب له name عند إستدعائها يجب أن نمرر لها إسم المستخدم مكان الباراميتر ،greeting هنا قمنا بتعريف دالة إسمها
// هو باراميتر إختياري تحدد من خلاله اللغة التي سيتم طباعة رسالة الترحيب بها، إفتراضياً رسالة الترحيب ستكون بالإنجليزية language
function greeting(name, language='English') {
switch(language) {
case 'English':
document.write(`Hello ${name}, welcome to codafox.blogspot.com <br>`);
break;
case 'French':
document.write(`Bonjour ${name}, bienvenue sur codafox.blogspot.com <br>`);
break;
default:
document.write('Selected language not available! <br>');
}
}
// 'English' و بالتالي ستظل قيمته language بدون تمرير قيمة مكان الباراميتر greeting() هنا قمنا باستدعاء الدالة
greeting('Ahmed');
// 'French' و بالتالي ستصبح قيمته language للباراميتر 'French' مع تمرير القيمة greeting() هنا قمنا باستدعاء الدالة
greeting('Ahmed', 'French');
</script>
</body>
</html>
بناء دوال تقبل عدد غير محدد من القيم
في بعض الأحيان قد تحتاج إلى بناء دالة يمكنها استقبال عدد غير محدد من القيم عند استدعائها. أي مهما كان عدد القيم التي ستمررها لها فإنها يجب أن تعالجهم كلهم.
في جافاسكربت يجب وضع الرمز
الباراميتر الذي يوجد قبله الرمز
و عندما يكون عدد القيم التي يمكن تمريرها للباراميتر غير محدد فإنه يقال لهذه القيم Variable-length Arguments.
في المثال التالي قمنا بتعريف دالة إسمها
جميع القيم التي سيتم تمريرها لها، سيتم تخزينها في باراميتر واحد إسمه
المثال الأول
<!DOCTYPE html>
<html>
<body>
<script>
// عند إستدعائها يمكننا تمرير عدد غير محدد من القيم لها. بعدها ستقوم بطباعة القيم التي مررناها لها printAll هنا قمنا بتعريف دالة إسمها
function printAll(...args) {
for (let e of args) {
document.write(e + '<br>');
}
}
// مع تمرير 10 قيم لها printAll() هنا قمنا بإستدعاء الدالة
printAll(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
</script>
</body>
</html>
في المثال التالي قمنا بتعريف دالة إسمها
الهدف من هذه الدالة طباعة مجموع كل القيم التي يتم تمريرها له.
جميع القيم التي سيتم تمريرها لها، سيتم تخزينها في باراميتر واحد إسمه
المثال الثاني
<!DOCTYPE html>
<html>
<body>
<script>
// عند إستدعائها يمكننا تمرير عدد غير محدد من القيم لها. بعدها ستقوم بطباعة ناتج جمع هذه القيم printSum هنا قمنا بتعريف دالة إسمها
function printSum(...values) {
let total = 0;
for (let val of values) {
total += val;
}
document.write('Total sum = ' + total);
}
// مع تمرير 5 قيم لها printSum() هنا قمنا بإستدعاء الدالة
printSum(1, 2, 3, 4, 5);
</script>
</body>
</html>
في المثال التالي قمنا بتعريف دالة إسمها
عند إستدعائها يجب أن نمرر لها قيمتين على الأقل:
- القيمة الأولى تمثل إسم شخص و الذي سنقوم بتخزينه في باراميتر إسمه
user . - القيمة الثانية أو مجموعة القيم الثانية تمثل نقاط هذا الشخص و التي سنقوم بتخزينها في باراميتر واحد إسمه
...points .
المثال الثالث
// points و نقاطه مكان الباراميتر user عند إستدعائها نمرر لها إسم الشخص مكان الباراميتر printUserScore هنا قمنا بتعريف دالة إسمها
// و عندها ستقوم بحساب مجموع نقاط هذا الشخص و من ثم ستعرض إسمه و إجمالي النقاط التي أحرزها بشكل مرتب
function printUserScore(user, ..<!DOCTYPE html>
<html>
<body>
<script>
// points و نقاطه مكان الباراميتر user عند إستدعائها نمرر لها إسم الشخص مكان الباراميتر printUserScore هنا قمنا بتعريف دالة إسمها
// و عندها ستقوم بحساب مجموع نقاط هذا الشخص و من ثم ستعرض إسمه و إجمالي النقاط التي أحرزها بشكل مرتب
function printUserScore(user, ...points) {
let total = 0;
for (let point of points) {
total += point;
}
document.write(`${user} score is: ${total}`);
}
// مع تمرير إسم الشخص و 5 قيم (و التي تمثل النقاط التي أحرزها) لها printUserScore() هنا قمنا بإستدعاء الدالة
printUserScore('Ahmed', 3, 5, 4, 2, 6);
</script>
</body>
</html>
عند وضع باراميتر في الدالة يقبل أكثر من قيمة فإنه يجب وضعه دائماً كآخر باراميتر فيها و إلا سيسبب ذلك خطأ في الكود.
إسناد الدالة إلى متغير
يمكنك تعريف الدالة بدون إسم و من ثم إسنادها إلى متغير ليصبح استخدام هذا المتغير يساوي استدعاء الدالة نفسها.
الفكرة الأساسية من هذا الأسلوب، هي تجهيز الكود الأساسي ليعمل بناءاً على الأوامر التي يتم تمريرها له في هذه الدالة.
أسلوب تعريف متغير يساوي دالة يقال له تعبير وظيفي ( Function Expression ).
الدالة التي لا تملك إسم يقال لها دالة مجهولة الإسم ( Anonymous Function ).
في المثال التالي قمنا بتعريف دالة بدون إسم و من ثم قمنا بإسنادها إلى المتغير
الدالة فكرتها أن تستقبل باراميتر عبارة عن إسم المستخدم، لتقوم بطباعة رسالة ترحيب له.
المثال الأول
<!DOCTYPE html>
<html>
<body>
<script>
// greeting هنا قمنا بتعريف دالة و إسنادها إلى المتغير
let greeting = function(name) {
document.write('Hello ' + name + '<br>');
}
// greeting هنا قمنا باستدعاء الدالة بواسطة المتغير
greeting('Ahmed');
</script>
</body>
</html>
الدالة التي يتم تعريفها بأسلوب Function Expression يتعرّف عليها مفسّر جافاسكربت عندما يقوم بتنفيذها فقط و هذا الفرق الأساسي بينها و بين الدوال التي يتم تعريفها بإسم محدد فيكون بالإمكان استدعاءها من أي مكان في الكود.
في حال قمت باستدعاء دالة تم تعريفها بأسلوب Function Expression قبل أن يتعرّف عليها مفسّر جافاسكربت فإن ذلك سيسبب الخطأ Uncaught ReferenceError.
في المثال التالي قمنا بتعريف دالة بدون إسم و من ثم قمنا بإسنادها إلى المتغير
الدالة فكرتها أن تستقبل باراميتر عبارة عن إسم المستخدم، لتقوم بطباعة رسالة ترحيب له.
المثال الثاني
<!DOCTYPE html>
<html>
<body>
<script>
// و التي ستتنفذ بشكل طبيعي لأن مفسّر جافاسكربت يعلم أنه يوجد دالة بهذا الإسم declaration() هنا قمنا باستدعاء الدالة
declaration();
// و التي يمكن استدعاءها من أي مكان لأن مفسر الكود علم بوجودها declaration هنا قمنا بتعريف دالة إسمها
function declaration() {
document.write('The declaration function is called.<br>');
}
// و هذا الأمر سيسبب مشكلة لأن مفسّر جافاسكربت لا يعلم بعد بوجودها expression() هنا قمنا باستدعاء الدالة
expression();
// هذا الأمر لن يتنفذ أساساً بسبب الخطأ في الأمر السابق <== expression هنا قمنا بتعريف دالة و إسنادها إلى المتغير
let expression = function() {
document.write('The expression function is called.<br>');
}
</script>
</body>
</html>
حل مشكلة تضارب الأسماء
عند تعريف دوال جديدة عليك الإنتباه لأسماء الباراميترات و المتغيرات التي تنوي تعريفها فيها حتى لا يحدث تضارب في الأسماء بينها و بين باقي المتغيرات الموجودة خارجها، بمعنى آخر حتى لا تقع في مشكلة تضارب الأسماء ( Name Conflict ).
المتغيرات التي يتم تعريفها بداخل الدوال يقال لها متغيرات محليّة ( Local Variables ) و هذه المتغيرات لا يمكن الوصول إليها من خارج الدوال فهي خاصة فيها.
المتغيرات التي يتم تعريفها خارج الدوال يقال لها متغيرات عامة ( Global Variables ) لأنه يمكن الوصول لها من أي مكان في الكود حتى من داخل الدوال ما لم يكن هناك تضارب في الأسماء.
متى يحدث تضارب الأسماء
في حال قمت بتعريف متغير إسمه
في المثال التالي قمنا بتعريف متغير إسمه
المثال الأول
<!DOCTYPE html>
<html>
<body>
<script>
// قيمته تساوي 1 x هنا قمنا بتعريف متغير إسمه
let x = 1;
// الذي تم تعريفه خارجها x تطبع قيمة المتغير printX هنا قمنا بتعريف دالة إسمها
function printX() {
document.write('Global x =' + x);
}
// الذي تم تعريفه خارجها x و التي ستطبع قيمة المتغير printX() هنا قمنا باستدعاء الدالة
printX();
</script>
</body>
</html>
في المثال التالي قمنا بتعريف متغير إسمه
هنا سيتم طباعة قيمة
المثال الثاني
<!DOCTYPE html>
<html>
<body>
<script>
// قيمته تساوي 1 x هنا قمنا بتعريف متغير إسمه
let x = 1;
// الذي تم تعريفه بداخلها x تطبع قيمة المتغير printX هنا قمنا بتعريف دالة إسمها
function printX() {
let x = 5;
document.write('Local x =' + x + '<br>');
}
// الذي تم تعريفه بداخلها x و التي ستطبع قيمة المتغير printX() هنا قمنا باستدعاء الدالة
printX();
// الموجود خارج الدالة. لاحظ أن قيمته لم تتغير x هنا قمنا بطباعة قيمة المتغير
document.write('Global x =' + x);
</script>
</body>
</html>
إذا أردت استخدام أسماء المتغيرات العامة في ذات الوقت كأسماء لمتغيرات محلية فهنا يمكنك إضافة الرمز
في المثال التالي قمنا بتعريف متغير إسمه
هنا سيتم طباعة قيمة
المثال الثالث
<!DOCTYPE html>
<html>
<body>
<script>
// قيمته تساوي 1 x هنا قمنا بتعريف متغير إسمه
let x = 1;
// الذي تم تعريفه بداخلها x تطبع قيمة المتغير printBoth هنا قمنا بتعريف دالة إسمها
function printBoth() {
let _x = 5;
document.write('Local x =' + _x + '<br>');
document.write('Global x =' + x + '<br>');
}
// _x و x و التي ستطبع قيم المتغيرين printX() هنا قمنا باستدعاء الدالة
printBoth();
</script>
</body>
</html>
في درس قادم سنتعرف على أسلوب آخر و مهم جداً لتعريف الدوال يسمى الدوال السهميّة ( Arrow Functions ) و الذي يمكن استخدامه لتعريف الدوال بشكل مختصر 🙂