--- title: الدوال slug: Web/JavaScript/Guide/Functions tags: - الدوال - جافا سكريبت - دليل translation_of: Web/JavaScript/Guide/Functions original_slug: Web/JavaScript/Guide/الدوال ---
الدوال هي واحدة من اللبنات الأساسية في جافاسكريبت. الدالة، هي عبارة عن مجموعة من التعليمات البرمجية التي تؤدي وظيفة معينة. حتى تتمكن من إستخدام الدالة، عليك أولا تعريفها في مكان ما من النطاق الذي تود إستدعائها منه.
يمكنك القاء نظرة في مرجع مفصل عن دوال الجافاسكريبت حتى تتعرف على تفاصيل اكثر.
تعريف الدالة: تتكون الدالة من الكلمة المحجوزة function، متبوعة بـ :
على سبيل المثال، الكود التالي يعرف دالة بسيطة تسمى square
:
function square(number) { return number * number; }
الدالة square
تمتلك بارامتر واحد، هو number
. وتعليمة برمجية واحدة تقوم بإرجاع بارامتر الدالة number
مضروباً في نفسه. والتعليمة return تحدد القيمة التي سترجعها الدالة.
return number * number;
يتم تمرير البارامترات الاولية primitives (
كالسلاسل الحرفية، الاعداد...الخ)
الى الدالة، بوسيلة تسمى، الاستدعاء بالقيمة، call by value وهي، ان يتم تحليل argument
الدالة، والقيمة الناتجة سَتُرسل نسخة منها فقط إلى المتغير المستقبل (بارامتر الدالة)، بعد ذالك تقوم الدالة بتخزين هذه القيمة في الذاكرة، ثم، إذا كانت الدالة قادرة على تعيين القيم للبارامترات الخاصة بها، تبدا بالعمل على هذه النسخة فقط، دون تغيير اي شئ في قيمة المتغير الاصلي.
في المثال التالي، لدينا المتغير value
سنقوم بتمريره إلى الدالة square. ثم ضمن الدالة square سيتم إنشاء نسخة جديدة، وهكذا، حتى وان قمنا بتغيير القيمة داخل الدالة، فلن يؤثر هذا على قيمة المتغير الأصلي الذي تم تعريفه خارج الدالة. لان هذا التغيير لن يكون مرئيا خارج الدالة:
function square(number) { // parameter = recipient return number * number; } var value = 10; square(value); // argument = Sender document.write(value); // log: 10
على عكس المثال السابق، اذا قمت بتمرير كائن (مثلا، قيمة غير اولية ك {{jsxref("Array")}} او كائن معرف من قبل المستخدم) كبارامتر، وقامت الدالة بتغيير خصائص الكائن، سيكون هذا التغيير مرئيا خارج الدالة:
function myFunc(theObject) { theObject.make = "Toyota"; } var mycar = {make: "Honda", model: "Accord", year: 1998}; var x, y; x = mycar.make; // x gets the value "Honda" myFunc(mycar); y = mycar.make; // y gets the value "Toyota" // (the make property was changed by the function)
في حين ان الدالة اعلاه تم الاعلان عنها بصيغة function declaration
، يمكن ايضا انشاء الدوال بصيغة ال function expression
. كما يمكن ايضا للدوال ان تكون بصيغة ال anonymous
(دوال مجهولة الاسم). على سبيل المثال، الدالة square
يمكن تعريفها ايضا بصيغة ال function expression
على النحو التالى:
var square = function(number) { return number * number }; var x = square(4) // x gets the value 16
يمكن تعيين اسم للدوال بصيغة ال function expression
، لجعل الدالة تعيد استدعاء ذاتها (الاستدعاء الداتي)، أو استخدامه في المنقح debugger. او لتعقب اخطاء الدالة من خلال stack traces.
var factorial = function fac(n) { return n<2 ? 1 : n*fac(n-1) }; console.log(factorial(3));
يمكنك تمرير دالة كبارامتر لدالة اخرى. يظهر المثال التالي الدالة map
تستخدم دالة اخرى كبارامتر اول لها :
function map(f,a) { var result = [], // Create a new Array i; for (i = 0; i != a.length; i++) result[i] = f(a[i]); return result; }
طريقة استخدامها مع الصيغة function expression:
var multiply = function(x) { return x * x * x; }; map(multiply, [0, 1, 2, 5, 10]);
طريقة استخدامها مع الصيغة anonymous function
مباشرة:
map(function(x) {return x * x * x}, [0, 1, 2, 5, 10]);
returns [0, 1, 8, 125, 1000].
في الجافاسكريبت يمكن الاعلان عن دالة اعتمادا على شرط. على سبيل المثال، ستقوم التعليمة البرمجية التالية بالاعلان عن الدالة myFunc
شرط ان يكون num
يساوي 0:
var myFunc; if (num === 0){ myFunc = function(theObject) { theObject.make = "Toyota" } }
بالإضافة إلى انشاء الدوال كما هو موضح اعلاه، يمكنك ايضا استخدام الصيغة {{jsxref("Function")}} constructor
لانشاء دوال من خلال السلاسل النصية، تنفذ وقت التشغيل، تماما كما في {{jsxref("eval", "()eval")}}.
هناك فرق بين الدوال (functions
) والوظائف (methods
)، الدوال هي ما نناقشه في هذا الفصل، والوظائف هي تلك المرتبطة بالكائنات (قيمة لخاصية في الكائن)، اقرأ المزيد حول الكائنات والوظائف العمل مع الكائنات [عربي].
تعريف الدالة يعني ببساطة إعطاء إسم لها وتحديد ماستقوم به عندما يتم إستدعائها. أما إستدعاء الدالة فيقوم فعليا بتنفيذ الإجراءات مع البرامترات المحددة. على سبيل المثال، إذا قمت بتعريف الدالة square، فستقوم بإستدعائها كما يلي :
square(5);
تقوم التعليمة البرمجية اعلاه باستدعاء الدالة مع البارامتر 5. ثم تقوم بتنفيذ التعليمات البرمجية المرتبطة بها وترجع القيمة 25.
الدوال يجب ان تنتمي للنطاق الذي استدعيت فيه، ولان الدوال بصيغة function declaration
ترفع اعلى النطاق، فمن الممكن أن تعرف في وقت لاحق، كما في المثال التالي:
console.log(square(5)); /* ... */ function square(n) { return n*n }
نطاق الدالة هو اما الدالة التي تم الإعلان عنها، أو البرنامج بأكمله إذا تم الاعلان عنها في المستوى العلوي.
ملاحظة: سيعمل هذا فقط عندما يتم تعريف الدالة باستخدام الصيغة (مثل {}
()function funcName
). اما التعليمة البرمجية التالية فسوف لن تعمل، وهذا يعني ان الية الرفع (hoisting) بالنسبة للدوال تعمل فقط مع الدوال ذات الصيغة function declaration ولا تعمل مع الدوال ذات الصيغة function expression.
console.log(square); // square is hoisted with an initial value undefined. console.log(square(5)); // TypeError: square is not a function var square = function(n) { return n * n; }
arguments
الدالة لا تقتصر على الاعداد او السلاسل الحرفية فقط، يمكنك تمرير الكائنات ايضا. في القسم الخاص بالعمل مع الكائنات العمل مع الكائنات[عربي] توجد دالة باسم ()
showProps
توضح كيفية تمرير كائن ك argument
للدالة.
يمكن للدالة أن تقوم بإستدعاء ذاتها. على سبيل المثال، هذه الدالة تقوم بحساب المضروب بشكل متكرر :
function factorial(n){ if ((n === 0) || (n === 1)) return 1; else return (n * factorial(n - 1)); }
في كل مرة تقوم الدالة باستدعاء ذاتها، يتم خصم 1 من قيمة البرامتر الممرر، ويتم ضرب القيمة المحصلة في القيمة العائدة من جديد، فرضا، اذا كانت القيمة الممررة 5، الاستدعاء الاول سيكون 5، الاستدعاء الثاني سيكون 4، الاستدعاء الثالث سيكون 3، وهكذا، ويتم ضرب هذه القيم العائدة مع بعضها البعض. بهذا الشكل : 5 * 4 * 3 * 2 * 1 == 120
امثلة متنوعة:
var a, b, c, d, e; a = factorial(1); // a gets the value 1 // 1 * 1 b = factorial(2); // b gets the value 2 // 2 * 1 c = factorial(3); // c gets the value 6 // 3 * 2 * 1 d = factorial(4); // d gets the value 24 // 4 * 3 * 2 * 1 e = factorial(5); // e gets the value 120 // 5 * 4 * 3 * 2 * 1
هناك طرق أخرى لاستدعاء الدوال. غالبا ما تكون هناك حالات تحتاج الى دالة تُستدعى بشكل ديناميكي، حيث يمكن التعامل مع مجموعة من ال arguments
، وحيث سياق (context)
استدعاء الدالة يجب ان ينشا في وظيفة لكائن يحدد وقت التشغيل. وهذا يبين ان الدوال هي نفسها كائنات، وهذه الكائنات بدورها لديها وظائف ( شاهد {{jsxref("Function")}} object). من ضمن هذه الوظائف، الوظيفة {{jsxref("Function.apply", "()apply")}} يمكن استخدامها لتحقيق هذه الاهداف.
المتغيرات المعرفة داخل الدالة لايمكن الوصول إليها من أي مكان آخر خارج الدالة، لأن هذه المتغيرات معرفة فقط داخل نطاق الدالة. على كل، يمكن للدالة الوصول إلى كل المتغيرات والدوال المعرفة في النطاق المعرفة فيه الدالة. بعبارة أخرى، الدالة المعرفة في النطاق العام تستطيع الوصول إلى كل المتغيرات المعرفة في النطاق العام. الدالة المعرفة داخل دالة أخرى يمكنها أيضا الوصول إلى كل المتغيرات المعرفة في دالتها الأم وكل المتغيرات الأخرى التي يمكن للدالة الأم الوصول لها.
// المتغيرات التالية معرفة في النطاق العام var num1 = 20, num2 = 3, name = "Chamahk"; // هذه الدالة معرفة في النطاق العام function multiply() { return num1 * num2; } multiply(); // Returns 60 // مثال على دالة داخل دالة function getScore () { var num1 = 2, num2 = 3; function add() { return name + " scored " + (num1 + num2); } return add(); } getScore(); // Returns "Chamahk scored 5"
يمكن للدالة ان تستدعي داتها بثلاثة طرق:
arguments.callee
على سبيل المثال، انظر الدالة التالية:
var foo = function bar() { // statements go here };
تضمين الاستدعاء الذاتي داخل جسم الدالة bar
:
()bar
()arguments.callee
()foo
الدوال التي تقوم باستدعاء نفسها تسمى recursive function. الاستدعاء الداتي يشبه آلِية الحلقات في بعض النواحي، كلاهما ينفذان التعليمات البرمجية نفسها عدة مرات، وايضا كلاهما يتطلبان تعبيرا شرطيا (لتجنب التكرار الى ما لا نهاية، او بالاحرى، الاستدعاء الذاتي الى ما لا نهاية في حالتنا هذه). على سبيل المثال، الحلقة التالية:
var x = 0; while (x < 10) { // "x < 10" is the loop condition // do stuff x++; }
المثال التالي يبين دالة تقوم بالاستدعاء الذاتي، يمكنها محاكات الحلقة :
function loop(x) { if (x >= 10) // "x >= 10" is the exit condition (equivalent to "!(x < 10)") return; // do stuff loop(x + 1); // the recursive call } loop(0);
ومع ذلك، لا يمكن أن تكون بعض الخوارزميات حلقات تكرارية بسيطة. على سبيل المثال، الوصول الى كافة العقد nodes
في بنية الشجرة DOM
سيكون اسهل واكثر تفصيلا باستخدام الاستدعاء الذاتي:
function walkTree(node) { if (node == null) // return; // do something with node for (var i = 0; i < node.childNodes.length; i++) { walkTree(node.childNodes[i]); } }
على عكس الحلقات التكرارية البسيطة، والتي تقوم بالتكرار السطحي على DOM
، تمكننا دوال الاستدعاء الداتي من تنفيذ عدة استدعاءات، كل استدعاء داتي ينتج عنه العديد من الاستدعاءات الفرعية، بمعنى ان هذا النوع من الدوال يمكنها الوصول الى عمق ال DOM
. لتتيح لك امكانية التعامل مع كل جزئية فيه. كما يوضح المثال التالي:
var walkTree = function recycle( node, fn ) { fn( node ); node = node .firstChild; while( node ){ recycle( node, fn ); node = node.nextSibling; } } walkTree( document.body , function( node ){ if( node.nodeType == 1 ){ // do something with [object HTMLElements] } if( node.nodeType == 3 ){ // do something with [object Text] } });
كلا الدالتين اعلاه، تؤدي نفس الغرض، لا اختلاف بينهما، الفرق الوحيد هو شكل بناء الدالة، حيث بنيت الدالة الاولى على طريقة ال function declaration
فيما بنيت الدالة الثانية على شكل، ال function expression
وال anonymous function
، وكلاهما تنتهج اسلوب recursive function.
من الناحية النظرية، من الممكن تحويل أي خوارزمية الاستدعاء الذاتي الى خوارزمية الاستدعاء العادي (مع الحلقات، على سبيل المثال). عموما، المنطق الناتج أكثر تعقيداً ويتطلب استخدام المكدس. الاستدعاء الذاتي أيضا يستخدم المكدس، مكدس الدالة function stack
.
سلوك مكدس الذاكرة المؤقتة يمكن أن ينظر إليه كما في المثال التالي:
function foo(i) { if (i < 0) return; console.log('begin:' + i); foo(i - 1); console.log('end:' + i); } foo(3); // Output: // begin:3 // begin:2 // begin:1 // begin:0 // end:0 // end:1 // end:2 // end:3
يمكن انشاء دالة داخل دالة اخرى. الدالة الداخلية هي دالة خاصة private
بالدالة الخارجة. الدالة الداخلية تشكل الاغلاق closure
، والإغلاق هو فقط تعبير (عموما الاغلاق هو دالة). والذي يمكنه الوصول إلى المتغيرات المجانية free variables (المصطلح free variable يشير الى المتغيرات المستخدمة في الدالة، وهي ليست متغيرات محلية او بارامترات لهذه الدالة. بمعنى اخر هي متغيرات معرفة خارج الدالة وتستفيد منها الدالة، وهذا هو سبب تسميتها بالمتغيرات المجانية)، كما يمكنه ايضا، الوصول الى اي شئ في البيئة التي ترتبط بها هذه المتغيرات المجانية.
بما ان الدالة الداخلية هي closure
. فهذا يعني انها تستطيع ان ترث البرامترات والمتغيرات من الدالة الخارجية. بمعنى اخر، الدالة الداخلية تمتلك النطاق الخاص بالدالة الخارجية.
الخلاصة:
closure
: الدالة الداخلية يمكنها استخدام البرامترات والمتغيرات الخاصة بالدالة الخارجية، فيما لا يمكن للدالة الخارجية استخدام البرامترات والمتغيرات الخاصة بالدالة الداخلية.يظهر المثال التالي الدوال المتداخلة:
function addSquares(a,b) { function square(x) { return x * x; } return square(a) + square(b); } a = addSquares(2,3); // returns 13 b = addSquares(3,4); // returns 25 c = addSquares(4,5); // returns 41
بما ان الدالة الداخلية تشكل closure
. فمن الضروري استدعاء الدالة الخارجية أولا، بعد ذالك يمكنك تحديد ال arguments
لكل منهما :
function outside(x) { function inside(y) { return x + y; } return inside; } fn_inside = outside(3); // Think of it like: give me a function that adds 3 to whatever you give it result = fn_inside(5); // returns 8 result1 = outside(3)(5); // returns 8
في المثال اعلاه، لاحظ كيف تم الحفاظ على x
عندما تم ارجاع الدالة inside
. الاغلاق يحفاظ على البرامترات والمتغيرات في جميع النطاقات التي تشير إليه. مع كل استدعاء للدالة الخارجية، يمكنك تعيين arguments
مختلفة، سيتم إنشاء إغلاق جديد مع كل استدعاء للدالة outside
. يمكن تحرير الذاكرة فقط عندما يكون عائد الدلة inside
غير متاحا.
وهذا لا يختلف عن تخزين المراجع في كائنات أخرى، ولكن غالبا ما يكون أقل وضوحاً نظراً لعدم تعيين المراجع مباشرة ولا يمكن فحصها.
الدوال يمكن ان تكون اكثر تداخلا، بمعنى، الدالة (A)
تحتضن الدالة (B)
، والدالة (B)
تحتضن الدالة (C)
. هنا كل من الدالة B و C
تشكل closures
، وهكذا B
يمكنها الوصول الى A
، و C
يمكنها الوصول الى B
. بالاضافة الى ذالك، C
يمكنها الوصول الى B و A
، وبالتالي، الإغلاق يمكن أن يحتوي على عدة نطاقات. وهذا ما يسمى بسلسلة النطاق scope chaining. (سيتم شرح لماذا يطلق عليه "تسلسل
" في وقت لاحق).
انظر في المثال التالي:
function A(x) { function B(y) { function C(z) { console.log(x + y + z); } C(3); } B(2); } A(1); // logs 6 (1 + 2 + 3)
في هذا المثال C
تصل الى y
الخاصة ب B
وايضا الى x
الخاصة ب A
، أصبح هذا ممكناً لأن:
B
تشكل closure، وتمتلك A
، بمعنى B
يمكنها الوصول الى البارامترات والمتغيرات الخاصة ب A
.C
تشكل closure
، وتمتلك B
.B
تمتلك A
، فقد اصبح C
يمتلك A
، وعليه ف C
يمكنه الوصول الى البارامترات والمتغيرات الخاصة ب B و A
. بعبارات أخرى، C
سلسلة نطاقات ل B
و A
في هذا الترتيب.العكس ليس صحيحاً. A
لا يمكنها الوصول الى C
، لان A
لا يمكنها الوصول لاي من البارامترات او المتغيرات الخاصة ب B
. (فيما C
هي متغير لها). وهكذا، C
ستصبح خاصة private
فقط ب B
.
عند وجود اثنين من البارامترات أو المتغيرات التي تحمل نفس الاسم في نطاقات الاغلاق، فهذا يسمى تضارب في الاسماء، وفي هذه الحالة، ستكون الاسبقية للنطاقات الاكثر عمقا في استخدام هذا الاسم، اما بالنسبة للنطاقات الأكثر سطحية سوف تحظى بأولوية أدنى لاستخدام هذا الاسم، من وجهة نظر سلسلة النطاق، النطاق الاول في السلسلة هو النطاق الاكثر عمقا ( اسفل السلسلة)، والنطاق الاخير في السلسلة هو النطاق الاكثر سطحية (اعلى السلسلة). شاهد المثال التالي:
function outside() { var x = 10; function inside(x) { return x; } return inside; } result = outside()(20); // returns 20 instead of 10
يحدث تعارض الاسم في التعليمة return
x
، وهو مابين الباراميتر x
الخاص ب inside
وبين المتغير x
الخاص ب outside
. سلسلة النطاق سترى الامر على هذا النحو {inside, outside, global object}
. وبناءا عليه x
الخاص ب inside
سياخد الاسبقية على x
الخاص ب outside
، وبالتالي الناتج هو 20 (inside x) بدلا من 10 (outside x).
الإغلاق هي واحدة من أقوى المميزات في جافا سكريبت. جافا سكريبت تسمح بتداخل الوظائف وتمنح الدوال الداخلية حق الوصول الكامل إلى كافة المتغيرات والدوال المعرفة داخل الدالة الخارجية (وجميع المتغيرات والدوال الأخرى التي يمكن للدالة الخارجية الوصول إليها). ومع ذالك، الدوال الخارجية لا يمكنها الوصول الى المتغيرات والدوال المعرفة داخل الدوال الداخلية. وهذا يوفر نوعا من الحماية للمتغيرات والدوال الداخلية. وأيضا، لأن الدوال الداخلية لديها حق الوصول إلى نطاق الدالة الخارجية، فالمتغيرات والدوال المعرفة داخل الدالة الخارجية ستدوم اطول من مدة تنفيذ الدالة الخارجىة، اذا تمكنت الدالة الداخلية ان تدوم أطول من الدالة الخارجية. يتم إنشاء الاغلاق عندما تكون الدالة الداخلية بطريقة أو بأخرى في متناول أي نطاق خارج الدالة الخارجية.
var pet = function(name) { // The outer function defines a paramrter called "name" var getName = function() { return name; // The inner function has access to the "name" paramrter of the outer function } return getName; // Return the inner function, thereby exposing it to outer scopes }, myPet = pet("Vivie"); myPet(); // Returns "Vivie"
من الناحية العملية، يمكن أن تكون المسالة أكثر تعقيداً من التعليمات البرمجية أعلاه. يمكن إرجاع كائن والذي سيحتوي على وظائف للتعامل مع المتغيرات الداخلية للدالة الخارجية:
var createPet = function(name) { var sex; return { setName: function(newName) { name = newName; }, getName: function() { return name; }, getSex: function() { return sex; }, setSex: function(newSex) { if(typeof newSex === "string" && (newSex.toLowerCase() === "male" || newSex.toLowerCase() === "female")) { sex = newSex; } } } } var pet = createPet("Vivie"); pet.getName(); // Vivie pet.setName("Oliver"); pet.setSex("male"); pet.getSex(); // male pet.getName(); // Oliver
في التعليمات البرمجية اعلاه، المتغير name
الخاص بالدالة الخارجية يمكن الوصول اليه من الدوال الداخلية. من المعلوم ايضا، انه، ليس هناك طريقة أخرى للوصول إلى المتغيرات الداخلية إلا من خلال الدوال الداخلية. المتغيرات الداخلية الخاصة بالدوال االداخلية هي بمثابة مخازن آمنة بالنسبة للبارامترات و المتغيرات الخارجية. كما انها تتيح امكانية الوصول الى البيانات الداخلية بشكل دقيق وامن. بالنسبة للدوال، ليس من الضروري تعيينها إلى متغير أو حتى تسميتها.
var getCode = (function(){ var secureCode = "0]Eal(eh&2"; // A code we do not want outsiders to be able to modify... return function () { return secureCode; }; })(); getCode(); // Returns the secureCode
ومع ذلك، يجب الاحتراس جيدا من الوقوع في بعض الفخاخ عند استخدام عمليات الإغلاق. إذا كانت دالة مغلقة تعرف متغير بنفس الاسم، كاسم متغير في النطاق الخارجي، فلا توجد طريقة للإشارة إلى المتغير في النطاق الخارجي مرة أخرى.
var createPet = function(name) { // Outer function defines a variable called "name" return { setName: function(name) { // Enclosed function also defines a variable called "name" name = name; // ??? How do we access the "name" defined by the outer function ??? } } }
الكلمة المحجوزة this
(في بعض الاحيان تسمى بالمتغير العجيب)، ينبغي التعامل معها بحذر في حالات الإغلاق. احذر، ف this
تشير إلى السياق حيث سيتم استدعاء الدالة وليس إلى المكان حيث تم تعريف الدالة.
يمكنك التعامل مع arguments
الدالة من الداخل، من خلال الكائن (arguments او الحجج
). يمكنك معالجة ال arguments
الممررة الى الدالة على النحو التالي:
arguments[i]
حيث ان i
هو الفهرس الرقمي لل arguments
، ويبتدئ من 0
، وبالتالي، ال argument
الاول الممرر الى الدالة سيكون arguments[0]
. لمعرفة عدد ال argument
s
الممررة نستخدم arguments.length
.
باستخدام الكائن arguments
، يمكنك استدعاء دالة مع arguments
أكثر من التي تم التصريح بها رسميا. وهي مفيذة جدا، خصوصا إذا كنت لا تعرف مسبقاً كم عدد ال arguments
التي ستمرر اثناء استدعاء الدالة. يمكنك استخدام arguments.length
لمعرفة عدد البرامترات الممرة الى الدالة، حتى تتمكن بعد ذالك من التعامل معها من خلال الكائن arguments
.
على سبيل المثال، يمكننا انشاء دالة تقوم بوصل عدة سلاسل حرفية. ال argument
الوحيد المحدد رسميا في الدالة، هو السلسلة الحرفية التي ستفصل بين باقي السلاسل الحرفية التي ستمرر ك arguments
بعد ال argument
الرسمي للدالة. كما في المثال التالي:
function myConcat(separator) { var result = "", // initialize list i; // iterate through arguments for (i = 1; i < arguments.length; i++) { result += arguments[i] + separator; } return result; }
يمكنك تمرير اي عدد من ال arguments
لهذه الدالة، وسترتبط ببعضها البعض من خلال ما سيمرر الى ال argument
الرسمي:
// returns "red, orange, blue, " myConcat(", ", "red", "orange", "blue"); // returns "elephant; giraffe; lion; cheetah; " myConcat("; ", "elephant", "giraffe", "lion", "cheetah"); // returns "sage. basil. oregano. pepper. parsley. " myConcat(". ", "sage", "basil", "oregano", "pepper", "parsley");
ملاحظة: المتغير arguments هو شبه مصفوفة، ولكنه ليس مصفوفة. وانما يتصرف كالمصفوفة، يستخدم الفهرسة الرقمية، يستخدم الخاصية length، ومع ذالك، لا يمكنه استخدام الوظائف الخاصة بالمصفوفات مثل push او join ...الخ.
Function parameters
او بارامترات الدالة، هي الأسماء المدرجة في تعريف الدالة. فيما Function arguments
هي القيم الحقيقية التي تمرر إلى الدالة عند الاستدعاء (
راجع التعريف والاستدعاء اعلى الصفحة)
. انظر المثال التالي:
function foo( param1, param2, ...) // parameters { // Do things } foo(arg1, arg2, ...); // arguments
ملاحظة: ال parameter
هو متغير باسم معين يمرر الى الدالة. تستخدم الباراميترات لجلب ال arguments
داخل الدوال.
راجع الكائن {{jsxref("Function")}} في مرجع الجافا سكريبت لمزيد من المعلومات.
بدأً من ECMAScript 6، أصبح هناك نوعان من البارامترات: البارامترات الإفتراضية وبقية البارامترات.
في الجافاسكريبت، القيمة الافتراضية لبرامترات الدوال هي undefined
. ومع ذالك، في بعض الحالات، قد يكون من المفيد تعيين قيمة افتراضية مختلفة. البارامترات الافتراضية يمكنها تدارك الموقف.
قبل ECMAScript 2015، كانت الاستراتيجية العامة لوضع الافتراضات هي اختبار قيمة البارامتر في جسم الدالة وتعيين قيمة له اذا كانت قيمته undefined
. على سبيل المثال، في التعليمة البرمجية التالية، لم يتم تحديد قيمة للبارامتر b
في الاستدعاء، وبالتالي قيمتة ستساوي undefined
، عند اختبار (a * b)
ستعود الدالة multiply
ب NaN
. لتجنب هذا، يقوم السطر الثاني في التعليمة البرمجية اسفله بتعيين قيمة افتراضية للبارامتر b
:
function multiply(a, b) { b = typeof b !== 'undefined' ? b : 1; return a*b; } multiply(5); // 5
ابتداءا من ECMAScript 2015، اصبح من الممكن عمل اعدادات افتراضية على غرار (php)
، والاختبار في جسم الدالة لم يعد ضروريا. الان، ببساطة يمكنك تعيين 1
كقيمة افتراضية للبارامتر b
في تعريف الدالة:
function multiply(a, b = 1) { return a*b; } multiply(5); // 5
لمزيد من التفاصيل، راجع default parameters في مرجع الجافاسكريبت.
الصيغة rest parameter تسمح بتمثيل عدد غير محدود من ال arguments
كمصفوفة. في هذا المثال، نستخدم بقية البارامترات لتجميع ال arguments
ابتداءا من البرامتر الثاني لغاية النهاية. ثم نقوم بضربها باول بارامتر. هذا المثال يستخدم دالة السهم، والتي سندرسها في القسم التالي.
function multiply(multiplier, ...theArgs) { return theArgs.map(x => multiplier * x); } var arr = multiply(2, 1, 2, 3); console.log(arr); // [2, 4, 6]
تعبيرات دوال السهم تسمح لك باستخدام تعبيرا أكثر إيجازاً من التعبير عن الوظائف الكلاسيكية. والقيمة this
يتم ربطها بشكل نحوي. فيما تكون دوال السهم مجهولة الاسم anonymous
. راجع ايضا هذه المدونة ES6 In Depth: Arrow functions.
اثنين من العوامل التي أثرت في مقدمة دوال السهم: الدوال المختصرة و lexical this
.
في بعض الأنماط الوظيفية، الدوال المختصرة هي موضع ترحيب. قارن التعليمات البرمجية التالية:
var a = [ "Hydrogen", "Helium", "Lithium", "Beryllium" ]; var a2 = a.map(function(s){ return s.length }); var a3 = a.map( s => s.length );
التعليمة
Lexical this
قبل وجود وظائف السهم، كانت كل دالة جديدة تعرف قيمة ال this
الخاصة بها (كائن جديد في حالة الدالة الإنشائية، undefined
في استدعاءات الدوال مع الوضع الصارم، في سياق الكائن قيد التشغيل في حالة الوظيفة، إلخ.). وهذا يمكن أن يسبب بعض المشاكل مع نمط البرمجة الكائنية:
function Person() { // The Person() constructor defines 'this' as itself. this.age = 0; setInterval(function growUp() { // In nonstrict mode, the growUp() function defines 'this' // as the global object, which is different from the 'this' // defined by the Person() constructor. this.age++; }, 1000); } var p = new Person();
في ECMAScript 3/5، تم إصلاح هذه المشكلة عن طريق تخزير القيمة this
في متغير اخر.
function Person() { var self = this; // Some choose `that` instead of `self`. // Choose one and be consistent. self.age = 0; setInterval(function growUp() { // The callback refers to the `self` variable of which // the value is the expected object. self.age++; }, 1000); }
بدلا من ذلك، يمكننا إنشاء دالة ملزمة bound function بحيث تكون "احسن" قيمة this
سيتم تمريرها إلى الدالة ()growUp
.
دوال السهم تلتقط القيمة this من السياق المغلق (enclosing context)، لذا ستعمل التعليمة البرمجية التالية كما هو متوقع.
function Person(){ this.age = 0; setInterval(() => { this.age++; // |this| properly refers to the person object }, 1000); } var p = new Person();
جافا سكريبت لديها العديد من الوظائف المدمجة ذات المستوى الاعلى top-level :
الوظيفة ()
eval
تستخدم لاختبار شفرة الجافا سكريبت على شكل سلسلة حرفية.
الوظيفة ()
uneval
تستخدم لانشاء سلسلة حرفية عبارة عن مصدر كود الكائن {{jsxref("Object")}}.
الدالة العامة ()
isFinite
تقوم بتحديد ما إذا كانت القيمة التي تم تمريرها عدد محدود. إذا لزم الأمر، يتم تحويل البارامتر إلى رقم.
تستخدم الدالة()
isNaN
للتاكد من ان القيمة ليست رقمية {{jsxref("Global_Objects/NaN", "NaN")}} ملاحظة: يمكننا ايضا استخدام {{jsxref("Number.isNaN()")}}, الجديدة في ECMAScript 6 او استخدام التعليمة typeof
. كلها تادي نفس الغرض.
تستخدم الدالة ()
parseFloat
لتحويل سلسلة حرفية الى عدد كسري.
تستخدم الدالة ()
parseInt
لتحويل سلسلة حرفية الى عدد صحيح (البارامتر الثاني خاص بالتعامل مع القاعدة في الأنظمة العددية الرياضية).
تستخدم الدالة ()
decodeURI
لفك تشفير معرف الموارد الموحد (Uniform Resource Identifier (URI التي تم إنشاؤها مسبقا من طرف {{jsxref("Global_Objects/encodeURI", "encodeURI")}} او عن طريق نفس الروتين.
تستخدم الوظيفة ()
decodeURIComponent
لفك تشفير معرف عناصر الموارد الموحدة (Uniform Resource Identifier (URI التي تم إنشاؤها مسبقا من طرف {{jsxref("Global_Objects/encodeURIComponent", "encodeURIComponent")}} او عن طريق نفس الروتين.
تستخدم الوظيفة ()
encodeURI
لتشفير معرف الموارد الموحد (Uniform Resource Identifier (URI باستبدال كل مثيل من أحرف معينة بواحد، اثنان، ثلاثة، أو أربعة تهريبات متوالية تمثل ترميز الاحرف UTF-8 (لن يكون إلا أربع تهريبات متوالية لرموز تتألف من اثنين من الحروف "البديلة").
تستخدم الوظيفة ()
encodeURIComponent
لتشفير معرف عناصر الموارد الموحدة (Uniform Resource Identifier (URI باستبدال كل مثيل من أحرف معينة بواحد، اثنان، ثلاثة، أو أربعة تهريبات متوالية تمثل ترميز الاحرف UTF-8 (لن يكون إلا أربع تهريبات متوالية لاحرف تتألف من اثنين من الحروف "البديلة").
الوظيفة ()
escape
الغير مرغوب فيها. تحتسب سلسلة جديدة من بعض الأحرف التي يجب استبدلها من قبل hexadecimal escape sequence. استخدم {{jsxref("Global_Objects/encodeURI", "encodeURI")}} او استخدم {{jsxref("Global_Objects/encodeURIComponent", "encodeURIComponent")}} بدلا عنها.
الوظيفة()
unescape
الغير مرغوب فيها. تحتسب سلسلة جديدة بحيث hexadecimal escape sequence. اسبدلت مع الرمز الذي يمثلها. متتالية التهريب يمكن ان تاتى من دالة مثل {{jsxref("Global_Objects/escape", "escape")}}. على العموم استخدم {{jsxref("Global_Objects/decodeURI", "decodeURI()")}} او استخدم {{jsxref("Global_Objects/decodeURIComponent", "decodeURIComponent")}} بدلا عنها.
{{PreviousNext("Web/JavaScript/Guide/Loops_and_iteration", "Web/JavaScript/Guide/Expressions_and_Operators")}}