Programming Basics SQL HTML CSS JavaScript Python C++ Java JavaFX Swing Problem Solving English English Conversations Computer Fundamentals Learn Typing

جافاسكربتالدوال

  • مفهوم الدوال
  • تعريف دوال جديدة
  • وضع قيم إفتراضية للباراميترات
  • بناء دوال تقبل عدد غير محدد من القيم
  • إسناد الدالة إلى متغير
  • حل مشكلة تضارب الأسماء

مفهوم الدوال

الدالة ( Function ) عبارة عن مجموعة أوامر مجمعة في مكان واحد و تتنفذ عندما يتم استدعائها.
جافاسكربت تحتوي على مجموعة كبيرة جداً من الدوال الجاهزة و التي سبق أن إستخدامنا بعضها مثل الدوال document.write() و Math.max() و غيرهم من الدوال التي تطرقنا إليها في دروس سابقة.

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

الدوال الجاهزة في جافاسكربت يقال لها Built-in Functions.
الدوال التي يقوم المبرمج بتعريفها يقال لها User-defined Functions.

تعريف دوال جديدة

الشكل الأساسي الذي يجب إتباعه عند تعريف أي دالة في جافاسكربت هو التالي:

function name(parameters) {
    // statements
}
  • function: نستخدمها لتعريف دالة جديدة.
  • name: مكانها نضع الإسم الذي نريد إعطاؤه للدالة، و الذي من خلاله يمكننا استدعاءها.
  • parameters: هنا يمكنك وضع متغيرات، هذه المتغيرات تمرر لها قيم عند استدعاء الدالة.
  • statements: تعني الأوامر التي سنضعها في الدالة و التي ستتنفذ عند إستدعائها.

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


في المثال التالي قمنا بتعريف دالة إسمها demo وضعنا فيها أمر طباعة واحد فقط. بعدها قمنا باستدعائها.

المثال الأول

// demo هنا قمنا بتعريف دالة إسمها
function demo() {
document.write('My first function is called');
}
// حتى يتم تنفيذ الأمر الموضوع فيها demo هنا قمنا باستدعاء الدالة
demo();
// demo هنا قمنا بتعريف دالة إسمها function demo() { document.write('My first function is called'); } // حتى يتم تنفيذ الأمر الموضوع فيها demo هنا قمنا باستدعاء الدالة demo();
جرب الكود

هنا قمنا بتعريف دالة إسمها greeting عند إستدعائها نمرر لها إسم فتطبع رسالة ترحيب للإسم الذي تم تمريره لها.

المثال الثاني

// عند إستدعائها نمرر لها إسم, فتطبع جملة ترحيب بإسم الشخص الذي نمرره لها greeting هنا قمنا بتعريف دالة إسمها
function greeting(name) {
document.write('Hello ' + name + ' welcome to our company.');
}
// user هنا قمنا بتخزين إسم الشخص الذي سنمرره للدالة في المتغير
let user = 'Mhamad';
// حتى تطبع رسالة ترحيب له user و تمرير إسم الشخص الذي قمنا بتخزينه في المتغير greeting() هنا قمنا باستدعاء الدالة
greeting(user);
// عند إستدعائها نمرر لها إسم, فتطبع جملة ترحيب بإسم الشخص الذي نمرره لها greeting هنا قمنا بتعريف دالة إسمها function greeting(name) { document.write('Hello ' + name + ' welcome to our company.'); } // user هنا قمنا بتخزين إسم الشخص الذي سنمرره للدالة في المتغير let user = 'Mhamad'; // حتى تطبع رسالة ترحيب له user و تمرير إسم الشخص الذي قمنا بتخزينه في المتغير greeting() هنا قمنا باستدعاء الدالة greeting(user);
جرب الكود

المتغير الذي يتم تعريفه بين أقواس الدالة يسمى باراميتر ( Parameter ).
الباراميتر يُعتبر متغيّر محلّي ( Local Variable ) بالنسبة للدالة حيث أنه لا يمكن الوصول إليه من خارجها.


في المثال التالي قمنا بتعريف دالة إسمها getSum عند إستدعائها نمرر لها عددين فترجع لنا ناتج جمعهما.

المثال الثالث

// عند إستدعائها نمرر لها عددين فتقوم بإرجاع ناتج جمعهما get_sum هنا قمنا بتعريف دالة إسمها
function getSum(a, b) {
return a + b;
}
// x في المتغير getSum() هنا قمنا بتخزين ناتج العددين 3 و 5 الذي سترجعه الدالة
x = getSum(3, 5);
// و التي ستساوي 8 x هنا قمنا بعرض قيمة المتغير
document.write('x = ' + x);
// عند إستدعائها نمرر لها عددين فتقوم بإرجاع ناتج جمعهما get_sum هنا قمنا بتعريف دالة إسمها function getSum(a, b) { return a + b; } // x في المتغير getSum() هنا قمنا بتخزين ناتج العددين 3 و 5 الذي سترجعه الدالة x = getSum(3, 5); // و التي ستساوي 8 x هنا قمنا بعرض قيمة المتغير document.write('x = ' + x);
جرب الكود

إذاً في جافاسكربت نستخدم الكلمة return لجعل الدالة ترجع قيمة إلى المكان الذي تم فيه إستدعائها.

وضع قيم إفتراضية للباراميترات

جافاسكربت تتيح لك وضع قيم إفتراضية للباراميترات ليتم استخدامها بشكل تلقائي في حال تم استدعاء الدالة و لم يتم تمرير قيم للباراميترات الموضوعة فيها.

القيمة الإفتراضية التي يتم وضعها للباراميتر يقال لها Default Value أو Default Argument.


في المثال التالي قمنا بتعريف دالة إسمها greeting و فيها باراميترين:

  • الباراميتر الأول إسمه name و لا يملك قيمة إفتراضية.
  • الباراميتر الثاني إسمه language و يملك النص 'English' كقيمة إفتراضية.

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

مثال

// حتى تطبع رسالة ترحيب له name عند إستدعائها يجب أن نمرر لها إسم المستخدم مكان الباراميتر ،greeting هنا قمنا بتعريف دالة إسمها
// هو باراميتر إختياري تحدد من خلاله اللغة التي سيتم طباعة رسالة الترحيب بها، إفتراضياً رسالة الترحيب ستكون بالإنجليزية language
function greeting(name, language='English') {
switch(language) {
case 'English':
document.write(`Hello ${name}, welcome to harmash.com <br>`);
break;
case 'French':
document.write(`Bonjour ${name}, bienvenue sur harmash.com <br>`);
break;
default:
document.write('Selected language not available! <br>');
}
}
// 'English' و بالتالي ستظل قيمته language بدون تمرير قيمة مكان الباراميتر greeting() هنا قمنا باستدعاء الدالة
greeting('Mhamad');
// 'French' و بالتالي ستصبح قيمته language للباراميتر 'French' مع تمرير القيمة greeting() هنا قمنا باستدعاء الدالة
greeting('Mhamad', 'French');
// حتى تطبع رسالة ترحيب له name عند إستدعائها يجب أن نمرر لها إسم المستخدم مكان الباراميتر ،greeting هنا قمنا بتعريف دالة إسمها // هو باراميتر إختياري تحدد من خلاله اللغة التي سيتم طباعة رسالة الترحيب بها، إفتراضياً رسالة الترحيب ستكون بالإنجليزية language function greeting(name, language='English') { switch(language) { case 'English': document.write(`Hello ${name}, welcome to harmash.com <br>`); break; case 'French': document.write(`Bonjour ${name}, bienvenue sur harmash.com <br>`); break; default: document.write('Selected language not available! <br>'); } } // 'English' و بالتالي ستظل قيمته language بدون تمرير قيمة مكان الباراميتر greeting() هنا قمنا باستدعاء الدالة greeting('Mhamad'); // 'French' و بالتالي ستصبح قيمته language للباراميتر 'French' مع تمرير القيمة greeting() هنا قمنا باستدعاء الدالة greeting('Mhamad', 'French');
جرب الكود

بناء دوال تقبل عدد غير محدد من القيم

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

في جافاسكربت يجب وضع الرمز ... قبل إسم الباراميتر مباشرةً حتى يفهم المفسّر أنه يمكن تمرير عدد غير محدد من القيم مكانه.

الباراميتر الذي يوجد قبله الرمز ... يقال له Rest Parameter.
و عندما يكون عدد القيم التي يمكن تمريرها للباراميتر غير محدد فإنه يقال لهذه القيم Variable-length Arguments.


في المثال التالي قمنا بتعريف دالة إسمها printAll تقبل عدد غير محدد من القيم عند إستدعائها و ثم تقوم بعرض هذه القيم بواسطة الحلقة for of.
جميع القيم التي سيتم تمريرها لها، سيتم تخزينها في باراميتر واحد إسمه ...args.

المثال الأول

// عند إستدعائها يمكننا تمرير عدد غير محدد من القيم لها. بعدها ستقوم بطباعة القيم التي مررناها لها 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);
// عند إستدعائها يمكننا تمرير عدد غير محدد من القيم لها. بعدها ستقوم بطباعة القيم التي مررناها لها 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);
جرب الكود

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

المثال الثاني

// عند إستدعائها يمكننا تمرير عدد غير محدد من القيم لها. بعدها ستقوم بطباعة ناتج جمع هذه القيم 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);
// عند إستدعائها يمكننا تمرير عدد غير محدد من القيم لها. بعدها ستقوم بطباعة ناتج جمع هذه القيم 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);
جرب الكود

في المثال التالي قمنا بتعريف دالة إسمها printUserScore الهدف منها طباعة إسم الشخص و مجموع النقاط التي أحرزها.

عند إستدعائها يجب أن نمرر لها قيمتين على الأقل:

  • القيمة الأولى تمثل إسم شخص و الذي سنقوم بتخزينه في باراميتر إسمه user.
  • القيمة الثانية أو مجموعة القيم الثانية تمثل نقاط هذا الشخص و التي سنقوم بتخزينها في باراميتر واحد إسمه ...points.

المثال الثالث

// 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('Mhamad', 3, 5, 4, 2, 6);
// 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('Mhamad', 3, 5, 4, 2, 6);
جرب الكود

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

إسناد الدالة إلى متغير

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

أسلوب تعريف متغير يساوي دالة يقال له تعبير وظيفي ( Function Expression ).
الدالة التي لا تملك إسم يقال لها دالة مجهولة الإسم ( Anonymous Function ).


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

المثال الأول

// greeting هنا قمنا بتعريف دالة و إسنادها إلى المتغير
let greeting = function(name) {
document.write('Hello ' + name + '<br>');
}
// greeting هنا قمنا باستدعاء الدالة بواسطة المتغير
greeting('Mhamad');
// greeting هنا قمنا بتعريف دالة و إسنادها إلى المتغير let greeting = function(name) { document.write('Hello ' + name + '<br>'); } // greeting هنا قمنا باستدعاء الدالة بواسطة المتغير greeting('Mhamad');
جرب الكود

الدالة التي يتم تعريفها بأسلوب Function Expression يتعرّف عليها مفسّر جافاسكربت عندما يقوم بتنفيذها فقط و هذا الفرق الأساسي بينها و بين الدوال التي يتم تعريفها بإسم محدد فيكون بالإمكان استدعاءها من أي مكان في الكود.


في حال قمت باستدعاء دالة تم تعريفها بأسلوب Function Expression قبل أن يتعرّف عليها مفسّر جافاسكربت فإن ذلك سيسبب الخطأ Uncaught ReferenceError.


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

المثال الثاني

// و التي ستتنفذ بشكل طبيعي لأن مفسّر جافاسكربت يعلم أنه يوجد دالة بهذا الإسم 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>');
}
// و التي ستتنفذ بشكل طبيعي لأن مفسّر جافاسكربت يعلم أنه يوجد دالة بهذا الإسم 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>'); }
جرب الكود

حل مشكلة تضارب الأسماء

عند تعريف دوال جديدة عليك الإنتباه لأسماء الباراميترات و المتغيرات التي تنوي تعريفها فيها حتى لا يحدث تضارب في الأسماء بينها و بين باقي المتغيرات الموجودة خارجها، بمعنى آخر حتى لا تقع في مشكلة تضارب الأسماء ( Name Conflict ).

المتغيرات التي يتم تعريفها بداخل الدوال يقال لها متغيرات محليّة ( Local Variables ) و هذه المتغيرات لا يمكن الوصول إليها من خارج الدوال فهي خاصة فيها.
المتغيرات التي يتم تعريفها خارج الدوال يقال لها متغيرات عامة ( Global Variables ) لأنه يمكن الوصول لها من أي مكان في الكود حتى من داخل الدوال ما لم يكن هناك تضارب في الأسماء.


متى يحدث تضارب الأسماء

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


في المثال التالي قمنا بتعريف متغير إسمه x، ثم قمنا بتعريف دالة إسمها printX تقوم فقط بطباعة قيمته.

المثال الأول

// قيمته تساوي 1 x هنا قمنا بتعريف متغير إسمه
let x = 1;
// الذي تم تعريفه خارجها x تطبع قيمة المتغير printX هنا قمنا بتعريف دالة إسمها
function printX() {
document.write('Global x =' + x);
}
// الذي تم تعريفه خارجها x و التي ستطبع قيمة المتغير printX() هنا قمنا باستدعاء الدالة
printX();
// قيمته تساوي 1 x هنا قمنا بتعريف متغير إسمه let x = 1; // الذي تم تعريفه خارجها x تطبع قيمة المتغير printX هنا قمنا بتعريف دالة إسمها function printX() { document.write('Global x =' + x); } // الذي تم تعريفه خارجها x و التي ستطبع قيمة المتغير printX() هنا قمنا باستدعاء الدالة printX();
جرب الكود

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

المثال الثاني

// قيمته تساوي 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);
// قيمته تساوي 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);
جرب الكود

إذا أردت استخدام أسماء المتغيرات العامة في ذات الوقت كأسماء لمتغيرات محلية فهنا يمكنك إضافة الرمز _ قبل أسماء المتغيرات المحلية و هذا الأسلوب متعارف عليه بين المبرمجين.


في المثال التالي قمنا بتعريف متغير إسمه x، ثم قمنا بتعريف دالة إسمها printBoth تحتوي على متغير إسمه _x تقوم بطباعة قيمة كلا المتغيرين.
هنا سيتم طباعة قيمة x و _x من داخل الدالة بدون أي مشكلة لأنه لا يوجد تضارب في الأسماء.

المثال الثالث

// قيمته تساوي 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();
// قيمته تساوي 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();
جرب الكود

في درس قادم سنتعرف على أسلوب آخر و مهم جداً لتعريف الدوال يسمى الدوال السهميّة ( Arrow Functions ) و الذي يمكن استخدامه لتعريف الدوال بشكل مختصر 🙂