From 41c76addc97200aa71105773397aa4edd2af6b4c Mon Sep 17 00:00:00 2001 From: Florian Merz Date: Thu, 11 Feb 2021 14:44:35 +0100 Subject: unslug ar: move --- files/ar/web/javascript/guide/functions/index.html | 698 +++++++++++++++++++++ .../index.html" | 698 --------------------- .../index.html | 424 ------------- .../javascript/reference/functions/get/index.html | 165 +++++ .../web/javascript/reference/functions/index.html | 645 +++++++++++++++++++ .../reference/global_objects/number/index.html | 12 + .../index.html" | 12 - .../get/index.html" | 165 ----- .../index.html" | 645 ------------------- 9 files changed, 1520 insertions(+), 1944 deletions(-) create mode 100644 files/ar/web/javascript/guide/functions/index.html delete mode 100644 "files/ar/web/javascript/guide/\330\247\331\204\330\257\331\210\330\247\331\204/index.html" delete mode 100644 files/ar/web/javascript/introduction_to_object-oriented_javascript/index.html create mode 100644 files/ar/web/javascript/reference/functions/get/index.html create mode 100644 files/ar/web/javascript/reference/functions/index.html create mode 100644 files/ar/web/javascript/reference/global_objects/number/index.html delete mode 100644 "files/ar/web/javascript/reference/global_objects/\330\247\331\204\330\247\330\261\331\202\330\247\331\205/index.html" delete mode 100644 "files/ar/web/javascript/reference/\330\247\331\204\330\257\331\210\330\247\331\204/get/index.html" delete mode 100644 "files/ar/web/javascript/reference/\330\247\331\204\330\257\331\210\330\247\331\204/index.html" (limited to 'files/ar/web/javascript') diff --git a/files/ar/web/javascript/guide/functions/index.html b/files/ar/web/javascript/guide/functions/index.html new file mode 100644 index 0000000000..af934b397d --- /dev/null +++ b/files/ar/web/javascript/guide/functions/index.html @@ -0,0 +1,698 @@ +--- +title: الدوال +slug: Web/JavaScript/Guide/الدوال +tags: + - الدوال + - جافا سكريبت + - دليل +translation_of: Web/JavaScript/Guide/Functions +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Loops_and_iteration", "Web/JavaScript/Guide/Expressions_and_Operators")}}
+ +

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

+ +
+

يمكنك القاء نظرة في مرجع مفصل عن دوال الجافاسكريبت حتى تتعرف على تفاصيل اكثر.

+ +

انشاء الدوال

+ +

الاعلان عن الدوال - الصيغة الافتراضية - Function declarations

+ +

تعريف الدالة: تتكون الدالة من الكلمة المحجوزة 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 expressions

+ +

في حين ان الدالة اعلاه تم الاعلان عنها بصيغة  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"
+
+ +

النطاق ومكدس الدوال

+ +

الاستدعاء الذاتي

+ +

يمكن للدالة ان تستدعي داتها بثلاثة طرق:

+ +
    +
  1. من خلال اسم الدالة
  2. +
  3. arguments.callee
  4. +
  5. من خلال المتغيرات التي تشير إلى الدالة
  6. +
+ +

على سبيل المثال، انظر الدالة التالية:

+ +
var foo = function bar() {
+   // statements go here
+};
+
+ +

تضمين الاستدعاء الذاتي داخل جسم الدالة bar:

+ +
    +
  1. ()bar
  2. +
  3. ()arguments.callee
  4. +
  5. ()foo
  6. +
+ +

الدوال التي تقوم باستدعاء نفسها تسمى 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
+ +

الدوال المتداخلة  و الاغلاق (closures)

+ +

يمكن انشاء دالة داخل دالة اخرى. الدالة الداخلية هي دالة خاصة private بالدالة الخارجة. الدالة الداخلية تشكل الاغلاق closure، والإغلاق هو فقط تعبير (عموما الاغلاق هو دالة). والذي يمكنه الوصول إلى المتغيرات المجانية free variables (المصطلح free variable يشير الى المتغيرات المستخدمة في الدالة، وهي ليست متغيرات محلية او بارامترات لهذه الدالة. بمعنى اخر هي متغيرات معرفة خارج الدالة وتستفيد منها الدالة، وهذا هو سبب تسميتها بالمتغيرات المجانية)،  كما يمكنه ايضا، الوصول الى اي شئ في البيئة التي ترتبط بها هذه المتغيرات المجانية.

+ +

بما ان الدالة الداخلية هي 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، أصبح هذا ممكناً لأن:

+ +
    +
  1. B تشكل closure، وتمتلك A، بمعنى B يمكنها الوصول الى البارامترات والمتغيرات الخاصة ب A.
  2. +
  3. C تشكل closure، وتمتلك B.
  4. +
  5. بسبب ان B تمتلك A، فقد اصبح C يمتلك A، وعليه ف C يمكنه الوصول الى البارامترات والمتغيرات الخاصة ب B و A. بعبارات أخرى، C سلسلة نطاقات ل B و A في هذا الترتيب.
  6. +
+ +

العكس ليس صحيحاً. 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).

+ +

الاغلاقات - Closures

+ +

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

+ +
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 الممررة الى الدالة على النحو التالي:

+ +
arguments[i]
+
+ +

حيث ان i هو الفهرس الرقمي لل arguments، ويبتدئ من 0، وبالتالي، ال argument الاول الممرر الى الدالة سيكون arguments[0]. لمعرفة عدد ال arguments الممررة نستخدم 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 ...الخ.

+
+ +

الفرق بين parameters و arguments

+ +

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

+ +

الصيغة 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]
+ +

دوال السهم - Arrow functions

+ +

تعبيرات دوال السهم تسمح لك باستخدام تعبيرا أكثر إيجازاً من التعبير عن الوظائف الكلاسيكية. والقيمة this يتم ربطها بشكل نحوي. فيما تكون دوال السهم مجهولة الاسم anonymous. راجع ايضا هذه المدونة  ES6 In Depth: Arrow functions.

+ +

اثنين من العوامل التي أثرت في مقدمة دوال السهم: الدوال المختصرة و lexical this.

+ +

الدوال المختصرة

+ +

في بعض الأنماط الوظيفية، الدوال المختصرة هي موضع ترحيب. قارن التعليمات البرمجية التالية:

+ +
var a = [
+  "Hydrogen",
+  "Helium",
+  "Lithium",
+  "Beryl­lium"
+];
+
+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 :

+ +
+
{{jsxref("Global_Objects/eval", "()eval")}}
+
+

الوظيفة ()eval تستخدم لاختبار شفرة الجافا سكريبت على شكل سلسلة حرفية.

+
+
{{jsxref("Global_Objects/uneval", "()uneval")}} {{non-standard_inline}}
+
+

الوظيفة ()uneval تستخدم لانشاء سلسلة حرفية عبارة عن مصدر كود الكائن {{jsxref("Object")}}.

+
+
{{jsxref("Global_Objects/isFinite", "()isFinite")}}
+
+

الدالة العامة () isFinite تقوم بتحديد ما إذا كانت القيمة التي تم تمريرها عدد محدود. إذا لزم الأمر، يتم تحويل البارامتر إلى رقم.

+
+
{{jsxref("Global_Objects/isNaN", "()isNaN")}}
+
+

تستخدم الدالة()isNaN للتاكد من ان القيمة ليست رقمية {{jsxref("Global_Objects/NaN", "NaN")}}  ملاحظة: يمكننا ايضا استخدام {{jsxref("Number.isNaN()")}}, الجديدة في ECMAScript 6 او استخدام التعليمة typeof. كلها تادي نفس الغرض.

+
+
{{jsxref("Global_Objects/parseFloat", "()parseFloat")}}
+
+

تستخدم الدالة ()parseFloat لتحويل سلسلة حرفية الى عدد كسري.

+
+
{{jsxref("Global_Objects/parseInt", "()parseInt")}}
+
+

تستخدم الدالة ()parseInt لتحويل سلسلة حرفية الى عدد صحيح (البارامتر الثاني خاص بالتعامل مع القاعدة في الأنظمة العددية الرياضية).

+
+
{{jsxref("Global_Objects/decodeURI", "()decodeURI")}}
+
+

تستخدم الدالة ()decodeURI لفك تشفير معرف الموارد الموحد (Uniform Resource Identifier (URI التي تم إنشاؤها مسبقا من طرف {{jsxref("Global_Objects/encodeURI", "encodeURI")}} او عن طريق نفس الروتين.

+
+
{{jsxref("Global_Objects/decodeURIComponent", "()decodeURIComponent")}}
+
+

تستخدم الوظيفة ()decodeURIComponent لفك تشفير معرف عناصر الموارد الموحدة (Uniform Resource Identifier (URI التي تم إنشاؤها مسبقا من طرف {{jsxref("Global_Objects/encodeURIComponent", "encodeURIComponent")}} او عن طريق نفس الروتين.

+
+
{{jsxref("Global_Objects/encodeURI", "()encodeURI")}}
+
+

تستخدم الوظيفة ()encodeURI لتشفير معرف الموارد الموحد (Uniform Resource Identifier (URI باستبدال كل مثيل من أحرف معينة بواحد، اثنان، ثلاثة، أو أربعة تهريبات متوالية تمثل ترميز الاحرف UTF-8 (لن يكون إلا أربع تهريبات متوالية لرموز تتألف من اثنين من الحروف "البديلة").

+
+
{{jsxref("Global_Objects/encodeURIComponent", "()encodeURIComponent")}}
+
+

تستخدم الوظيفة ()encodeURIComponent لتشفير معرف عناصر الموارد الموحدة (Uniform Resource Identifier (URI باستبدال كل مثيل من أحرف معينة بواحد، اثنان، ثلاثة، أو أربعة تهريبات متوالية تمثل ترميز الاحرف UTF-8 (لن يكون إلا أربع تهريبات متوالية لاحرف تتألف من اثنين من الحروف "البديلة").

+
+
{{jsxref("Global_Objects/escape", "()escape")}} {{deprecated_inline}}
+
+

الوظيفة ()escape الغير مرغوب فيها. تحتسب سلسلة جديدة من بعض الأحرف التي يجب استبدلها من قبل hexadecimal escape sequence. استخدم {{jsxref("Global_Objects/encodeURI", "encodeURI")}} او استخدم {{jsxref("Global_Objects/encodeURIComponent", "encodeURIComponent")}} بدلا عنها.

+
+
{{jsxref("Global_Objects/unescape", "()unescape")}} {{deprecated_inline}}
+
+

الوظيفة()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")}}

diff --git "a/files/ar/web/javascript/guide/\330\247\331\204\330\257\331\210\330\247\331\204/index.html" "b/files/ar/web/javascript/guide/\330\247\331\204\330\257\331\210\330\247\331\204/index.html" deleted file mode 100644 index af934b397d..0000000000 --- "a/files/ar/web/javascript/guide/\330\247\331\204\330\257\331\210\330\247\331\204/index.html" +++ /dev/null @@ -1,698 +0,0 @@ ---- -title: الدوال -slug: Web/JavaScript/Guide/الدوال -tags: - - الدوال - - جافا سكريبت - - دليل -translation_of: Web/JavaScript/Guide/Functions ---- -
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Loops_and_iteration", "Web/JavaScript/Guide/Expressions_and_Operators")}}
- -

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

- -
-

يمكنك القاء نظرة في مرجع مفصل عن دوال الجافاسكريبت حتى تتعرف على تفاصيل اكثر.

- -

انشاء الدوال

- -

الاعلان عن الدوال - الصيغة الافتراضية - Function declarations

- -

تعريف الدالة: تتكون الدالة من الكلمة المحجوزة 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 expressions

- -

في حين ان الدالة اعلاه تم الاعلان عنها بصيغة  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"
-
- -

النطاق ومكدس الدوال

- -

الاستدعاء الذاتي

- -

يمكن للدالة ان تستدعي داتها بثلاثة طرق:

- -
    -
  1. من خلال اسم الدالة
  2. -
  3. arguments.callee
  4. -
  5. من خلال المتغيرات التي تشير إلى الدالة
  6. -
- -

على سبيل المثال، انظر الدالة التالية:

- -
var foo = function bar() {
-   // statements go here
-};
-
- -

تضمين الاستدعاء الذاتي داخل جسم الدالة bar:

- -
    -
  1. ()bar
  2. -
  3. ()arguments.callee
  4. -
  5. ()foo
  6. -
- -

الدوال التي تقوم باستدعاء نفسها تسمى 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
- -

الدوال المتداخلة  و الاغلاق (closures)

- -

يمكن انشاء دالة داخل دالة اخرى. الدالة الداخلية هي دالة خاصة private بالدالة الخارجة. الدالة الداخلية تشكل الاغلاق closure، والإغلاق هو فقط تعبير (عموما الاغلاق هو دالة). والذي يمكنه الوصول إلى المتغيرات المجانية free variables (المصطلح free variable يشير الى المتغيرات المستخدمة في الدالة، وهي ليست متغيرات محلية او بارامترات لهذه الدالة. بمعنى اخر هي متغيرات معرفة خارج الدالة وتستفيد منها الدالة، وهذا هو سبب تسميتها بالمتغيرات المجانية)،  كما يمكنه ايضا، الوصول الى اي شئ في البيئة التي ترتبط بها هذه المتغيرات المجانية.

- -

بما ان الدالة الداخلية هي 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، أصبح هذا ممكناً لأن:

- -
    -
  1. B تشكل closure، وتمتلك A، بمعنى B يمكنها الوصول الى البارامترات والمتغيرات الخاصة ب A.
  2. -
  3. C تشكل closure، وتمتلك B.
  4. -
  5. بسبب ان B تمتلك A، فقد اصبح C يمتلك A، وعليه ف C يمكنه الوصول الى البارامترات والمتغيرات الخاصة ب B و A. بعبارات أخرى، C سلسلة نطاقات ل B و A في هذا الترتيب.
  6. -
- -

العكس ليس صحيحاً. 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).

- -

الاغلاقات - Closures

- -

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

- -
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 الممررة الى الدالة على النحو التالي:

- -
arguments[i]
-
- -

حيث ان i هو الفهرس الرقمي لل arguments، ويبتدئ من 0، وبالتالي، ال argument الاول الممرر الى الدالة سيكون arguments[0]. لمعرفة عدد ال arguments الممررة نستخدم 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 ...الخ.

-
- -

الفرق بين parameters و arguments

- -

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

- -

الصيغة 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]
- -

دوال السهم - Arrow functions

- -

تعبيرات دوال السهم تسمح لك باستخدام تعبيرا أكثر إيجازاً من التعبير عن الوظائف الكلاسيكية. والقيمة this يتم ربطها بشكل نحوي. فيما تكون دوال السهم مجهولة الاسم anonymous. راجع ايضا هذه المدونة  ES6 In Depth: Arrow functions.

- -

اثنين من العوامل التي أثرت في مقدمة دوال السهم: الدوال المختصرة و lexical this.

- -

الدوال المختصرة

- -

في بعض الأنماط الوظيفية، الدوال المختصرة هي موضع ترحيب. قارن التعليمات البرمجية التالية:

- -
var a = [
-  "Hydrogen",
-  "Helium",
-  "Lithium",
-  "Beryl­lium"
-];
-
-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 :

- -
-
{{jsxref("Global_Objects/eval", "()eval")}}
-
-

الوظيفة ()eval تستخدم لاختبار شفرة الجافا سكريبت على شكل سلسلة حرفية.

-
-
{{jsxref("Global_Objects/uneval", "()uneval")}} {{non-standard_inline}}
-
-

الوظيفة ()uneval تستخدم لانشاء سلسلة حرفية عبارة عن مصدر كود الكائن {{jsxref("Object")}}.

-
-
{{jsxref("Global_Objects/isFinite", "()isFinite")}}
-
-

الدالة العامة () isFinite تقوم بتحديد ما إذا كانت القيمة التي تم تمريرها عدد محدود. إذا لزم الأمر، يتم تحويل البارامتر إلى رقم.

-
-
{{jsxref("Global_Objects/isNaN", "()isNaN")}}
-
-

تستخدم الدالة()isNaN للتاكد من ان القيمة ليست رقمية {{jsxref("Global_Objects/NaN", "NaN")}}  ملاحظة: يمكننا ايضا استخدام {{jsxref("Number.isNaN()")}}, الجديدة في ECMAScript 6 او استخدام التعليمة typeof. كلها تادي نفس الغرض.

-
-
{{jsxref("Global_Objects/parseFloat", "()parseFloat")}}
-
-

تستخدم الدالة ()parseFloat لتحويل سلسلة حرفية الى عدد كسري.

-
-
{{jsxref("Global_Objects/parseInt", "()parseInt")}}
-
-

تستخدم الدالة ()parseInt لتحويل سلسلة حرفية الى عدد صحيح (البارامتر الثاني خاص بالتعامل مع القاعدة في الأنظمة العددية الرياضية).

-
-
{{jsxref("Global_Objects/decodeURI", "()decodeURI")}}
-
-

تستخدم الدالة ()decodeURI لفك تشفير معرف الموارد الموحد (Uniform Resource Identifier (URI التي تم إنشاؤها مسبقا من طرف {{jsxref("Global_Objects/encodeURI", "encodeURI")}} او عن طريق نفس الروتين.

-
-
{{jsxref("Global_Objects/decodeURIComponent", "()decodeURIComponent")}}
-
-

تستخدم الوظيفة ()decodeURIComponent لفك تشفير معرف عناصر الموارد الموحدة (Uniform Resource Identifier (URI التي تم إنشاؤها مسبقا من طرف {{jsxref("Global_Objects/encodeURIComponent", "encodeURIComponent")}} او عن طريق نفس الروتين.

-
-
{{jsxref("Global_Objects/encodeURI", "()encodeURI")}}
-
-

تستخدم الوظيفة ()encodeURI لتشفير معرف الموارد الموحد (Uniform Resource Identifier (URI باستبدال كل مثيل من أحرف معينة بواحد، اثنان، ثلاثة، أو أربعة تهريبات متوالية تمثل ترميز الاحرف UTF-8 (لن يكون إلا أربع تهريبات متوالية لرموز تتألف من اثنين من الحروف "البديلة").

-
-
{{jsxref("Global_Objects/encodeURIComponent", "()encodeURIComponent")}}
-
-

تستخدم الوظيفة ()encodeURIComponent لتشفير معرف عناصر الموارد الموحدة (Uniform Resource Identifier (URI باستبدال كل مثيل من أحرف معينة بواحد، اثنان، ثلاثة، أو أربعة تهريبات متوالية تمثل ترميز الاحرف UTF-8 (لن يكون إلا أربع تهريبات متوالية لاحرف تتألف من اثنين من الحروف "البديلة").

-
-
{{jsxref("Global_Objects/escape", "()escape")}} {{deprecated_inline}}
-
-

الوظيفة ()escape الغير مرغوب فيها. تحتسب سلسلة جديدة من بعض الأحرف التي يجب استبدلها من قبل hexadecimal escape sequence. استخدم {{jsxref("Global_Objects/encodeURI", "encodeURI")}} او استخدم {{jsxref("Global_Objects/encodeURIComponent", "encodeURIComponent")}} بدلا عنها.

-
-
{{jsxref("Global_Objects/unescape", "()unescape")}} {{deprecated_inline}}
-
-

الوظيفة()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")}}

diff --git a/files/ar/web/javascript/introduction_to_object-oriented_javascript/index.html b/files/ar/web/javascript/introduction_to_object-oriented_javascript/index.html deleted file mode 100644 index 65ce0c788a..0000000000 --- a/files/ar/web/javascript/introduction_to_object-oriented_javascript/index.html +++ /dev/null @@ -1,424 +0,0 @@ ---- -title: مدخل إلى جافاسكريبت كائنية التوجه -slug: Web/JavaScript/Introduction_to_Object-Oriented_JavaScript -tags: - - الأفراد - - البرمجة الكائنية - - التغليف - - الجافاسكريبت - - المتوسط - - المجال - - المشيد - - ب.ك.ت - - كائن -translation_of: Learn/JavaScript/Objects -translation_of_original: Web/JavaScript/Introduction_to_Object-Oriented_JavaScript ---- -
{{jsSidebar("Introductory")}}
- -

كائنية التوجه حتى النخاع، ميزات جافا سكريبت القوية، القدرات المرنة {{Glossary("OOP")}}. يبدأ هذا المقال بمقدمة إلى البرمجة الكائنية التوجه، ثم مراجعات لنموذج كائن جافا سكريبت، و أخيراً يوضح مفاهيم البرمجة الكائنية التوجه في جافا سكريبت. لا يصف هذا المقال البناء اللغوي الجديد للبرمجة الكائنية التوجه في ECMAScript 6.

- -
-

مراجعة جافا سكريبت

- -

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

- -

البرمجة الكائنية التوجه (Object-oriented programming)

- -

إن البرمجة الكائنية (OOP) ما هي إلا نمط برمجي يَستخدم التجريد في إنشاء نماذج/نسخ لتجسيد العالم الحقيقي، وتَستخدم البرمجة الكائنية في ذلك أساليب مُتعدّدة من هذا النمط، فهي تستخدم الوحدات module، وتعدديّة الأشكال polymorphism والتغليف encapsulation، وتجدر الإشارة إلى أن معظم لغات البرمجة تدعم مفهوم OOP أمثال اللغات البرمجية: جافا، بايثون، روبي، وطبعًا جافا سكريبت.

- -

يُعالج أو لنقل يَتصور مفهوم البرمجة الكائنية OOP البرنامج كتشكيلة من الأشياء/الكائنات المتعاونة/المترابطة بدلًا من يتصوّره كتشكيلة من الدوال (functions) أو كسرد من الأوامر. ففي مفهوم OOP، كل كائن/شيء له القدرة على استقبال الرسائل، ومعالجة البيانات، وإرسال الرسائل إلى باقي الكائنات، ويُمكن اعتبار أنه لكل كائن object كينونة خاصة به ودور/وظيفة مستقلة عن الكائن الآخر.

- -

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

- -

مصطلحات البرمجة الكائنية

- -
-
-

المجال في البرمجة الكائنية Namespace

- -

ما هو إلا عبارة عن حاوي تسمح للمطوّر بتحزيم جميع الوظائف تحت اسم محدد وفريد.

- -

الصنف أو الفئة Class في البرمجة الكائنية

- -

يعتني الصنف بكل ما يتعلّق بميزات وخصائص الكائن، والصنف ما هو إلا قالب template تعريفي بخاصيات properties وبطُرق/وظائف methods الكائن object.

- -

الكائن Object في البرمجة الكائنية

- -

الكائن ما هو إلا حالة/أمثولة instance من صنف class.

- -

الخاصية property في البرمجة الكائنية

- -

ما هي إلا مميزات وخصائص الكائن، كاللون مثلًا.

- -

الطريقة أو الوظيفة Method في البرمجة الكائنية

- -

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

- -

المشيد Constructor في البرمجة الكائنية

- -

ما هو إلا طريقة method تُستدعى في لحظة استهلال instantiate الكائن، وعادةً ما يكون له نفس اسم الصنف الذي يحتويه.

- -

الوراثة Inheritance في البرمجة الكائنية

- -

يُمكن للصنف أن يرث مميزات من صنف آخر.

- -

التغليف Encapsulation في البرمجة الكائنية

- -

طريقة في تحزيم البيانات data والطُرق methods التي تستخدم البيانات.

- -

التجريد Abstraction في البرمجة الكائنية

- -

يجب على الاقتران الحاصل من: الوراثة والطُرق methods والخاصيات properties لكائن معقد وشائك التمثيل برمجيًا أن يعكس الواقع المراد محاكاته في البرمجة الكائنية.

- -

تعددية الأشكال Polymorphism في البرمجة الكائنية

- -

تحمل كلمة Poly بحد ذاتها المعنى "متعدد" وتحمل الكلمة morphism المعنى "أشكال، ويُشير المفهوم ككل إلى أن أكثر من صنف قد يُعرّف نفس الطريقة method أو الخاصية property.

-
-
- -

للحصول على وصف أكثر شمولية للبرمجة الكائنية التوجه، أنظر {{interwiki("wikipedia", "البرمجة كائنية التوجه")}} على ويكيبيديا.

- -

البرمجة المعتمدة على النموذج الأولي Prototype

- -

البرمجة المعتمدة على النموذج الأوّلي (Prototype-based programming) ما هي إلا نموذج من البرمجة الكائنية OOP ولكنها لا تستخدم الأصناف classes، بل تقوم أولًا بإعداد سلوك أي صنف class ما ومن ثم تُعيد استخدامه، ويُطلق البعض على هذا النموذج: البرمجة بلا أصناف classless، أو البرمجة المَبْدَئِية المنحى prototype-oriented، أو البرمجة المعتمدة على الأمثولة instance-based).

- -

يعود أصل اللغة المعتمدة على النموذج الأولي إلى لغة Self، والتي طوّرها David Ungar وRandall Smith، ولكن أسلوب البرمجة بدون أصناف class-less توسّع ونال شهرة كبيرة في العقد الأخير، واُعتمد من قبل العديد من اللغات البرمجية أشهرهم جافا سكريبت.

- -

 

- -

البرمجة الكائنية باستخدام جافا سكريبت

- -

المجال Namespace في جافا سكريبت

- -

المجال هو أشبه بمستوعب/بحاوية (container) تسمح للمطوّر في تحزيم وظائف تحت اسم فريد، أو اسم تطبيق محدد، ففي جافا سكريبت المجال هو مجرد كائن object كأي كائن آخر يحتوي على طُرق methods، وخاصيات properties، وحتى كائنات objects.

- -
-

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

-
- -

إن إنشاء مجال namespace في جافا سكريبت بسيطٌ للغاية، فمن خلال إنشاء كائن عام/مشترك/شامل global، ستصبح جميع المُتغيّرات variables والطرق methods، والدوال functions خاصياتٍ لهذا الكائن، ويٌقلل استخدام المجالات namespaces أيضًا من احتمالية تضارب الأسماء في التطبيق، منذ أن كل كائن من كائنات التطبيق ما هي إلى خاصيات كائن شامل/عام معرّفة على مستوى التطبيق.

- -

سيُنشئ في الخطوة التالية كائنًا عامًا global وبالاسم MYAPP:

- -
// مجال عالمي
-var MYAPP = MYAPP || {};
- -

يُظهر المثال السابق، كيف تم التأكّد أولًا فيما إذا كان MYAPP معرفًا (سواء في نفس الملف أو في آخر)، ففي حال الإيجاب سيُستخدم الكائن العام MYAPP، وفي حال عدم تعريفه مُسبقًا سيُنشئ كائنًا خالٍ وبالاسمMYAPP والذي سيغلّف encapsulate الطرق methods والدوال functions والمتغيرات variables والكائنات objects.

- -

كما يُمكن أيضًا إنشاء مجال فرعي sub-namespaces:

- -
// مجال فرعي
-MYAPP.event = {};
- -

يوضّح المثال التالي الصيغة المستخدمة في إنشاء مجال namespace وإضافة متغيرات ودوال:

- -
// إنشاء حاوي يدعى MYAPP.commonMethod للوظائف و الخصائص الشائعة
-MYAPP.commonMethod = {
-  regExForName: "", // تعريف تعبير نظامي للتحقق من الإسم
-  regExForPhone: "", // تعريف تعبير نظامي للهاتف، لا يوجد تحقق من الصحة
-  validateName: function(name){
-    // إفعل شيئا ما بالإسم، يمكنك الوصول إلى المتغير regExForName
-    // بإستعمال "this.regExForName"
-  },
-
-  validatePhoneNo: function(phoneNo){
-    // إفعل شيئا ما برقم الهاتف
-  }
-}
-
-// تعريفات الكائن مع الزظيفة في نفس الوقت
-MYAPP.event = {
-    addListener: function(el, type, fn) {
-    // بعض الأكواد
-    },
-    removeListener: function(el, type, fn) {
-    // بعض الأكواد
-    },
-    getEvent: function(e) {
-    // بعض اﻷكواد
-    }
-
-    // يمكن إضافة وظائف و خصائص أخرى
-}
-
-// البناء اللغوي لإستعمال وظيفة addListener:
-MYAPP.event.addListener("yourel", "type", callback);
- -

 

- -

الكائنات الأساسية/القياسية المبنية داخل لغة جافا سكريبت (Standard built-in objects)

- -

تتضمن لغة جافا سكريبت العديد من الكائنات في تركيبتها، على سبيل المثال، يوجد كائنات مثل Math،Object، Array، String، ويُظهر المثال التالي كيفيّة استخدام الكائن Math للحصول على رقم عشوائي باستخدام أحد طُرق method هذا الكائن وهي الطريقة ()random.

- -
console.log(Math.random());
-
- -
-

ملاحظة: يَفترض المثال السابق وجميع الأمثلة التالية في المقال وجود دالة function بالاسم()console.log معرّفة تعريفًا عامًا (globally)، مع العلم أن هذه الدالة ليست جزء من اللغة نفسها، ولكنها دالة متوفّرة في العديد من متصفحات الإنترنت لأغراض تشخيص الشيفرة البرمجية debugging.

-
- -

يُمكن العودة إلى مرجع لغة جافا سكريبت: الكائنات الأصلية المعيارية للحصول على قائمة بالكائنات المبينة داخل لغة جافا سكريبت نفسها.

- -

كل كائن في جافا سكريبت هو حالة/أمثولة instance من الكائن Object ويَرث كافة خاصياته properties وطُرقه methods.

- -

 

- -

الكائنات الخاصة
- الصنف (الفئة)

- -

لغة جافا سكريبت لغة من النوع prototype-based ولا تحتوي على العبارة class كما هو حال باقي لغات البرمجة الكائنية، كما في روبي أو بايثون، ويُربك هذا الأمر المبرمجين المعتادين على اللغات التي تعتمد على هذه العبارة أو المفهوم، وتستخدم جافا سكريبت بدلًا من ذلك الدوال functions لمحاكات مفهوم الأصناف classes، وتعريف صنف هو بسهولة تعريف أي دالّة:

- -
var Person = function () {};
-
- -

الكائن (أمثولة الصنف class instance)

- -

يتطلب إنشاء حالة/أمثولة instance جديدة من كائن obj استخدام العبارة new obj، وتعيين النتيجة إلى متغيّر بغرض الوصول إلى فيما بعد.

- -

عُرّف في الشيفرة السابقة صنف class بالاسم Person، وفي الشيفرة التالية، سيُنشئ حالتين/أمثولتين instances من هذا الصنف، الأولى بالاسم person1 والثانية بالاسم person2.

- -
var person1 = new Person();
-var person2 = new Person();
-
- -
فضلا أنظر {{jsxref("Object.create()")}} للحصول على وظيفة الإنشاء الجديدة الإضافية التي تنشأ حالة غير مهيأة
- -

المشيد The constructor

- -

يُستدعى المُشيّد constructor في لحظة الاستهلال instantiation (اللحظة التي يُنشئ فيها الكائن)، والمُشيّد ما هو إلا طريقة method من طُرق الصنف class، وفي جافا سكريبت تعمل الدالة على تشييد الكائن، ولذلك لا داعي إلى تعريف طريقة method من أجل عميلة التشييد، وكل إجراء مصرّح في الصنف class يُنفّذ في لحظة الاستهلال instantiation.

- -

يُستخدم المُشيّد في تعيين خاصيات properties الكائن، أو في استدعاء طُرق methods معينة لتحضير الكائن للاستخدام، وأما إضافة طُرق صنف وتعريفها يحدث باستخدام صيغة syntax مختلفة سنتطرّق إليها فيما بعد خلال المقال.

- -

تُظهر الشيفرة التالية كيف يُسجّل log (يُرسل رسالة نصية إلى طرفية المتصفح console) مُشيّد الصنفPerson رسالة نصية حينما يُستهل instantiated.

- -
var Person = function () {
-  console.log('تم إنشاء حالة');
-};
-
-var person1 = new Person();
-var person2 = new Person();
-
-
- -

الخاصية The property (خاصية الكائن object attribute)

- -

الخاصيات properties ما هي إلا متغيرات محتوات في الصنف class، وكل حالة/أمثولة من الكائن تمتلك هذه الخاصيات، وتُعيّن الخاصيات في دالة مُشيّد الصنف بحيثُ تُنشئ مع كل حالة/أمثولة instance.

- -

إن الكلمة المفتاحية this، والتي تُشير إلى الكائن الحالي، تسمح للمطوّر بالعمل مع الخاصيات من ضمن الصنف، والوصول (قراءةً وكتابةً) إلى الخاصية property من خارج الصنف يكون من خلال الصيغةInstanceName.Property كما هو الأمر في لغة C++ (سي بلس بلس) وJava والعديد من اللغات الأخرى، ومن داخل الصنف تُستخدم الصيغة this.Property للحصول على قيمة الخاصية أو لتعيين قيمتها.

- -

في الشيفرة التالية، عُرّفت الخاصية firstName للصنف Person وفي لحظة الاستهلال instantiation:

- -
var Person = function (firstName) {
-  this.firstName = firstName;
-  console.log('تم إنشاء حالة من Person');
-};
-
-var person1 = new Person('سفيان');
-var person2 = new Person('محمد');
-
-// Show the firstName properties of the objects
-console.log('الشخص1 هو ' + person1.firstName); // النتيجة ==> "الشخص1 هو سفيان"
-console.log('الشخص2 هو ' + person2.firstName); // النتيجة ==> "الشخص2 هو محمد"
-
- -

الطرق The methods

- -

الطرق methods ما هي إلا دوال (وتُعرّف كما تعرّف الدوال functions)، فيما عدا ذلك فهي تُشبه الخاصيات properties، واستدعاء طريقة method مشابه إلى الوصول إلى خاصيّة ما، ولكن مع إضافة () في نهاية اسم الطريقة، وربما مع مُعطيات arguments، ولتعريف طريقة، تُعيّن دالة إلى خاصيّة مُسمّات من خاصيّة الصنف prototype، ويُمكن فيما بعد استدعاء الطريقة على الكائن بنفس الاسم الذي عُيّن للدالة.

- -

في الشيفرة التالية، عُرّفت ومن ثم اُستخدِمت الطريقة ()sayHello للصنف Person.

- -
var Person = function (firstName) {
-  this.firstName = firstName;
-};
-
-Person.prototype.sayHello = function() {
-  console.log("مرحبا، أنا " + this.firstName);
-};
-
-var person1 = new Person("سفيان");
-var person2 = new Person("محمد");
-
-// إستدعاء طريقة Person sayHello.
-person1.sayHello(); // النتيجة ==>"مرحبا، أنا سفيان"
-person2.sayHello(); // النتيجة ==> "مرحبا، أنا محمد"
-
- -

إن الطُرق methods في جافا سكريبت ما هي إلا دالة كائن عادية مرتبطة مع كائن كخاصية property، وهذا يعني أنه يُمكن استدعاء الطُرق خارج السياق، كما في المثال التالي:

- -
var Person = function (firstName) {
-  this.firstName = firstName;
-};
-
-Person.prototype.sayHello = function() {
-  console.log("مرحبا، أنا " + this.firstName);
-};
-
-var person1 = new Person("سفيان");
-var person2 = new Person("محمد");
-var helloFunction = person1.sayHello;
-
-// النتيجة ==> "مرحبا، أنا سفيان"
-person1.sayHello();
-
-// النتيجة ==> "مرحبا، أنا محمد"
-person2.sayHello();
-
-// النتيجة ==> "مرحبا، أنا undefined" (أو أخطاء
-// TypeError في الوضع الصارم)
-helloFunction();
-
-// النتيجة ==> true
-console.log(helloFunction === person1.sayHello);
-
-// النتيجة ==> true
-console.log(helloFunction === Person.prototype.sayHello);
-
-// النتيجة ==> "مرحبا، أنا سفيان"
-helloFunction.call(person1);
- -

كما يُظهر المثال السابق، جميع الإحالات المستخدمة في استدعاء الدالة sayHello تُشير إلى نفس الدالةسواءً الاستدعاء الحاصل مع person1 أو Person.prototype أو حتى في المتغيّر helloFunctionوقيمة this خلال استدعاء الدالة يعتمد على الكيفية التي تُستدعى فيها، حيث تُشير الكلمة المفتاحيةthis إلى الكائن الحالي الذي تُستدعى عليه الطريقة method، بمعنى عندما تم استدعاء الطريقة()sayHello على الكائن person1 فإن this تُشير إلى الكائن person1، وعند استدعاء sayHelloعلى الكائن person2 فإن this تُشير إلى الكائن person2، ولكن إن تم الاستدعاء بطريقة مختلفة، فإنthis ستُعيّن تعينًا مختلفًا، فاستدعاء this من المتغيّر (كما في ()helloFunction) سيُعيّن this إلى الكائن العام global (والذي سيكون window في متصفح الإنترنت)، ومنذ أن هذا الكائن (على الأغلب) لا يملك الخاصّيّة firstName، ستكون النتيجة كما هو الحال في المثال السابق “Hello, I’m undefined”، كما يمكن دائمًا تعيين this صراحةً باستخدام Function#call (أو Function#apply) وهو كما كان في نهاية المثال.

- -
ملاحظة: أنظر المزيد حول this على call و apply
- -

الوراثة

- -

تُستخدم الوراثة في جافا سكريبت في إنشاء صنف class كمثيل مخصص لصنف أو أكثر (تدعم جافا سكريبت وراثة وحيدة فقط single inheritance)، ويُطلق على الصنف المخصص عادةً ابن (child)، ويطلق على الصنف الآخر عادةً  الأب (parent)، وفي جافا سكريبت يتمّ ذلك من خلال إسناد حالة/أمثولة من الصنف الأب إلى الصنف الابن، ومن ثم تخصيصه، وفي متصفحات الإنترنت الحديثة يُمكن استخدامObject.create في تحقيق الوراثة inheritance أيضًا.

- -
-

ملاحظة: لا تتفقد جافا سكريبت مُشيّد صنف الابن prototype.constructor (راجعObject.prototype)، وعليه يجب التصريح عن ذلك يدويًا، لمزيد من التفصيل راجع السؤال التالي علىStackoverflow.

-
- -

عُرّف في الشيفرة التالية الصنف Student كصنف ابن للصنف Person، ومن ثم أُعيد تعريف الطريقة()sayHello وأُضيفت الطريقة ()sayGoodBye علاوة على ذلك.

- -
// تعريف المشيد Person
-var Person = function(firstName) {
-  this.firstName = firstName;
-};
-
-// إضافة زوج من الطرق إلى Person.prototype
-Person.prototype.walk = function(){
-  console.log("أنا أتمشى!");
-};
-
-Person.prototype.sayHello = function(){
-  console.log("مرحبا، أنا " + this.firstName);
-};
-
-// تعريف مشيد Student
-function Student(firstName, subject) {
-  // إستدعاء المشيد اﻷب, التأكد (عن طريق الإستدعاء)
-  // من أن "this" وضعت بشكل صحيح أثناء اﻹستدعاء
-  Person.call(this, firstName);
-
-  // تهيئة خصائص الطالب المحددة
-  this.subject = subject;
-}
-
-// إنشاء كائن Student.prototype الذي يرث من Person.prototype.
-// ملاحظة: خطأ شائع أن يستعمل "new Person()" ﻹنشاء
-// Student.prototype. هذا غير صحيح لعدة أسباب،
-// ليس أقل أننا ليس لدينا أي شيء ﻹعطاء Person إلى المعامل "firstName".
-// الطريقة الصحيحة ﻹستدعاء Person هي في الأعلى حيث
-// إستدعيناه من Student.
-Student.prototype = Object.create(Person.prototype); // See note below
-
-// وضع الخاصية "constructor" للإشارة إلى Student
-Student.prototype.constructor = Student;
-
-// إستبدال الطريقة "sayHello"
-Student.prototype.sayHello = function(){
-  console.log("مرحبا، أنا " + this.firstName + ". أنا أدرس "
-              + this.subject + ".");
-};
-
-// إضافة الطريقة "sayGoodBye"
-Student.prototype.sayGoodBye = function(){
-  console.log("وداعا!");
-};
-
-// إستعمال المثال:
-var student1 = new Student("سفيان", "المناجم");
-student1.sayHello();   // "مرحبا، أنا سفيان. أنا أدرس المناجم."
-student1.walk();       // "أنا أتمشى!"
-student1.sayGoodBye(); // "وداعا!"
-
-// التحقق من أن instanceof يعمل بشكل صحيح
-console.log(student1 instanceof Person);  // true
-console.log(student1 instanceof Student); // true
-
- -

فيما يخص السطر ;(Student.prototype = Object.create(Person.prototype في الإصدارات القديمة من جافا سكريبت والتي لا تدعم Object.create يمكن إما استخدام بعض الحيل في خداع المتصفحات –هذه الخدع معروفة إما بالاسم polyfill أو shim—أو استخدام دالة تحقق نفس النتيجة كما في المثال التالي:

- -
function createObject(proto) {
-    function ctor() { }
-    ctor.prototype = proto;
-    return new ctor();
-}
-
-// الإستعمال:
-Student.prototype = createObject(Person.prototype);
-
- -
ملاحظة: أنظر Object.create للمزيد من المعلومات حول ما يقوم به, و الرقاقات للمحركات القديمة.
- -

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

- -
var Person = function(firstName) {
-  if (this instanceof Person) {
-    this.firstName = firstName;
-  } else {
-    return new Person(firstName);
-  }
-}
-
- -

التغليف Encapsulation

- -

ليس بالضرورة أن يعلم الصنف Student كيف تمّ تنفيذ/تعريف الطريقة ()walk للصنف Person لكي يستطيع استخدام تلك الطريقة، ولا يحتاج الصنف Student إلى تعريف تلك الطريقة صراحةً إلا إذا كان المطلوب التعديل عليها، ويُطلق على هذا الإجراء مفهوم التغليف encapsulation، والذي فيه يَحزم كل صنف البيانات والطُرق methods داخل وحدة/كينونة وحيدة.

- -

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

- -

التجريد Abstraction

- -

التجرير ما هو إلا ميكانيكية تسمح للمطوّر في تجسيد جانب من المشكلة التي يُعمل عليها، إما من خلال الوراثة inheritance (التخصيص specialization) أو التركيب composition، وتُحقق جافا سكريبت التخصيص من خلال الوراثة، والتركيب من خلال السماح لحالات/أمثولات الصنف لتكون قيمًا لخاصيات attributes الكائنات الأخرى.

- -

الصنف Function في جافا سكريبت يرث من الصنف Object (وهذا يوضّح التخصيص في هذا النموذج) والخاصية Function.prototype ما هي إلا حالة/أمثولة من الصنف Object (وهذا يوضّح جزئية التركيب composition).

- -
var foo = function () {};
-
-// النتيجة ==> "foo عبارة عن وظيفة: true"
-console.log('foo عبارة عن وظيفة: ' + (foo instanceof Function));
-
-// النتيجة ==> "foo.prototype عبارة عن كائن: true"
-console.log('foo.prototype عبارة عن كائن: ' + (foo.prototype instanceof Object));
- -

تعددية الأشكال Polymorphism

- -

كما أن جميع الطُرق methods والخاصيات properties معرّفة ضمن الخاصية prototype، فيُمكن لبقية الأصناف أن تُعرِّف طُرقًا methods بنفس الاسم، وستكون الطُرق في نطاق الصنف الذي عُرفت به، إلا إذا كان الصنفان على علاقة من نوع أب وابن parent-child، بمعنى آخر أحد الصنفان يرث من الآخر
-
- هذه المقالة تُرجمة الي العربية بواسطة : محمد أبرص

- -

ملاحظات

- -

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

- -

هناك تقنيات أخرى تجعل البرمجة الكائنية التوجه أكثر تقدما لكنها خارج نطاق الهذه المقالة التمهيدية.

-
- -

المراجع

- -
    -
  1. ويكيبيديا - البرمجة الكائنية التوجه
  2. -
  3. ويكيبيديا - البرمجة القائمة على النوذج
  4. -
  5. ويكيبيديا - التغليف (البرمجة الكائنية التوجه)
  6. -
- -

أنظر أيضا

- - diff --git a/files/ar/web/javascript/reference/functions/get/index.html b/files/ar/web/javascript/reference/functions/get/index.html new file mode 100644 index 0000000000..d3789ba7bd --- /dev/null +++ b/files/ar/web/javascript/reference/functions/get/index.html @@ -0,0 +1,165 @@ +--- +title: getter +slug: Web/JavaScript/Reference/الدوال/get +translation_of: Web/JavaScript/Reference/Functions/get +--- +
{{jsSidebar("Functions")}}
+ +

The get صينطاكس طعمنيققbinds an object property to a function that will be called when that property is looked up.

+ +
{{EmbedInteractiveExample("pages/js/functions-getter.html")}}
+ + + +

Syntax

+ +
{get prop() { ... } }
+{get [expression]() { ... } }
+ +

Parameters

+ +
+
prop
+
rty to bind to the given fun-tion.
+
expression
+
Starting with ECMAScript 2015, you can also use expressions for a computed property name to bind to the given function.
+
+ +

Description

+ +

احا الشبشب ضاع احا دا كان ةبصباع

+ +

It is not possible to simultaneously have a getter bound to a property and have that property actually hold a value, although it is possible to use a getter and a setter in conjunction to create a type of pseudo-property.

+ +

Note the following when working with the get syntax:

+ + + +

Examples

+ +

Defining a getter on new objects in object initializers

+ +

This will create a pseudo-property latest for object obj, which will return the last array item in log.

+ +
const obj = {
+  log: ['example','test'],
+  get latest() {
+    if (this.log.length === 0) return undefined;
+    return this.log[this.log.length - 1];
+  }
+}
+console.log(obj.latest); // "test"
+
+ +

Note that attempting to assign a value to latest will not change it.

+ +

Deleting a getter using the delete operator

+ +

If you want to remove the getter, you can just {{jsxref("Operators/delete", "delete")}} it:

+ +
delete obj.latest;
+
+ +

Defining a getter on existing objects using defineProperty

+ +

To append a getter to an existing object later at any time, use {{jsxref("Object.defineProperty()")}}.

+ +
const o = {a: 0};
+
+Object.defineProperty(o, 'b', { get: function() { return this.a + 1; } });
+
+console.log(o.b) // Runs the getter, which yields a + 1 (which is 1)
+ +

Using a computed property name

+ +
const expr = 'foo';
+
+const obj = {
+  get [expr]() { return 'bar'; }
+};
+
+console.log(obj.foo); // "bar"
+ +

Smart / self-overwriting / lazy getters

+ +

Getters give you a way to define a property of an object, but they do not calculate the property's value until it is accessed. A getter defers the cost of calculating the value until the value is needed. If it is never needed, you never pay the cost.

+ +

An additional optimization technique to lazify or delay the calculation of a property value and cache it for later access are smart (or "memoized") getters. The value is calculated the first time the getter is called, and is then cached so subsequent accesses return the cached value without recalculating it. This is useful in the following situations:

+ + + +
+

This means that you shouldn’t write a lazy getter for a property whose value you expect to change, because if the getter is lazy then it will not recalculate the value.

+ +

Note that getters are not “lazy” or “memozied” by nature; you must implement this technique if you desire this behavior.

+
+ +

In the following example, the object has a getter as its own property. On getting the property, the property is removed from the object and re-added, but implicitly as a data property this time. Finally, the value getsreturn this.notifier = document.getElementById('bookmarked-notification-anchor'); },

+ +

For Firefox code, see also the XPCOMUtils.jsm code module, which defines the defineLazyGetter() function.

+ +

get vs. defineProperty

+ +

While using the get keyword and {{jsxref("Object.defineProperty()")}} have similar results, there is a subtle difference between the two when used on {{jsxref("classes")}}.

+ +

When using get the property will be defined on the instance's prototype, while using {{jsxref("Object.defineProperty()")}} the property will be defined on the instance it is applied to.

+ +
class Example {
+  get hello() {
+    return 'world';
+  }
+}
+
+const obj = new Example();
+console.log(obj.hello);
+// "world"
+
+console.log(Object.getOwnPropertyDescriptor(obj, 'hello'));
+// undefined
+
+console.log(
+  Object.getOwnPropertyDescriptor(
+    Object.getPrototypeOf(obj), 'hello'
+  )
+);
+// { configurable: true, enumerable: false, get: function get hello() { return 'world'; }, set: undefined }
+ +

Specifications

+ + + + + + + + + + + + +
Specification
{{SpecName('ESDraft', '#sec-method-definitions', 'Method definitions')}}
+ +

Browser compatibility

+ + + +

{{Compat("javascript.functions.get")}}

+ +

See also

+ + diff --git a/files/ar/web/javascript/reference/functions/index.html b/files/ar/web/javascript/reference/functions/index.html new file mode 100644 index 0000000000..368d8af03d --- /dev/null +++ b/files/ar/web/javascript/reference/functions/index.html @@ -0,0 +1,645 @@ +--- +title: الدوال +slug: Web/JavaScript/Reference/الدوال +translation_of: Web/JavaScript/Reference/Functions +--- +
{{jsSidebar("Functions")}}
+ +

Generally speaking, a function is a "subprogram" that can be called by code external (or internal in the case of recursion) to the function. Like the program itself, a function is composed of a sequence of statements called the function body. Values can be passed to a function, and the function will return a value.

+ +

In JavaScript, functions are first-class objects, because they can have properties and methods just like any other object. What distinguishes them from other objects is that functions can be called. In brief, they are Function objects.

+ +

For more examples and explanations, see also the JavaScript guide about functions.

+ +

Description

+ +

Every function in JavaScript is a Function object. See {{jsxref("Function")}} for information on properties and methods of Function objects.

+ +

Functions are not the same as procedures. A function always returns a value, whereas a procedure might not.

+ +

To return a value other than the default, a function must have a return statement that specifies the value to return. A function without a return statement will return a default value. In the case of a constructor called with the new keyword, the default value is the value of its this parameter. For all other functions, the default return value is undefined.

+ +

The parameters of a function call are the function's arguments. Arguments are passed to functions by value. If the function changes the value of an argument, this change is not reflected globally or in the calling function. However, object references are values, too, and they are special: if the function changes the referred object's properties, that change is visible outside the function, as shown in the following example:

+ +
/* Declare the function 'myFunc' */
+function myFunc(theObject) {
+   theObject.brand = "Toyota";
+ }
+
+ /*
+  * Declare variable 'mycar';
+  * create and initialize a new Object;
+  * assign reference to it to 'mycar'
+  */
+ var mycar = {
+   brand: "Honda",
+   model: "Accord",
+   year: 1998
+ };
+
+ /* Logs 'Honda' */
+ console.log(mycar.brand);
+
+ /* Pass object reference to the function */
+ myFunc(mycar);
+
+ /*
+  * Logs 'Toyota' as the value of the 'brand' property
+  * of the object, as changed to by the function.
+  */
+ console.log(mycar.brand);
+
+ +

The this keyword does not refer to the currently executing function, so you must refer to Function objects by name, even within the function body.

+ +

Defining functions

+ +

There are several ways to define functions:

+ +

The function declaration (function statement)

+ +

There is a special syntax for declaring functions (see function statement for details):

+ +
function name([param[, param[, ... param]]]) {
+   statements
+}
+
+ +
+
name
+
The function name.
+
+ +
+
param
+
The name of an argument to be passed to the function. A function can have up to 255 arguments.
+
+ +
+
statements
+
The statements comprising the body of the function.
+
+ +

The function expression (function expression)

+ +

A function expression is similar to and has the same syntax as a function declaration (see function expression for details):

+ +
function [name]([param[, param[, ... param]]]) {
+   statements
+}
+
+ +
+
name
+
The function name. Can be omitted, in which case the function becomes known as an anonymous function.
+
+ +
+
param
+
The name of an argument to be passed to the function. A function can have up to 255 arguments.
+
statements
+
The statements comprising the body of the function.
+
+ +

The generator function declaration (function* statement)

+ +
+

Note: Generator functions are an experimental technology, part of the ECMAScript 6 proposal, and are not widely supported by browsers yet.

+
+ +

There is a special syntax for generator function declarations (see {{jsxref('Statements/function*', 'function* statement')}} for details):

+ +
function* name([param[, param[, ... param]]]) {
+   statements
+}
+
+ +
+
name
+
The function name.
+
+ +
+
param
+
The name of an argument to be passed to the function. A function can have up to 255 arguments.
+
+ +
+
statements
+
The statements comprising the body of the function.
+
+ +

The generator function expression (function* expression)

+ +
+

Note: Generator functions are an experimental technology, part of the ECMAScript 6 proposal, and are not widely supported by browsers yet.

+
+ +

A generator function expression is similar to and has the same syntax as a generator function declaration (see {{jsxref('Operators/function*', 'function* expression')}} for details):

+ +
function* [name]([param[, param[, ... param]]]) {
+   statements
+}
+
+ +
+
name
+
The function name. Can be omitted, in which case the function becomes known as an anonymous function.
+
+ +
+
param
+
The name of an argument to be passed to the function. A function can have up to 255 arguments.
+
statements
+
The statements comprising the body of the function.
+
+ +

The arrow function expression (=>)

+ +
+

Note: Arrow function expressions are an experimental technology, part of the ECMAScript 6 proposal, and are not widely supported by browsers yet.

+
+ +

An arrow function expression has a shorter syntax and lexically binds its this value (see arrow functions for details):

+ +
([param[, param]]) => {
+   statements
+}
+
+param => expression
+
+ +
+
param
+
The name of an argument. Zero arguments need to be indicated with ().  For only one argument, the parentheses are not required. (like foo => 1)
+
statements or expression
+
Multiple statements need to be enclosed in brackets. A single expression requires no brackets. The expression is also the implicit return value of the function.
+
+ +

The Function constructor

+ +
+

Note: Using the Function constructor to create functions is not recommended since it needs the function body as a string which may prevent some JS engine optimizations and can also cause other problems.

+
+ +

As all other objects, {{jsxref("Function")}} objects can be created using the new operator:

+ +
new Function (arg1, arg2, ... argN, functionBody)
+
+ +
+
arg1, arg2, ... argN
+
Zero or more names to be used by the function as formal parameters. Each must be a proper JavaScript identifier.
+
+ +
+
functionBody
+
A string containing the JavaScript statements comprising the function body.
+
+ +

Invoking the Function constructor as a function (without using the new operator) has the same effect as invoking it as a constructor.

+ +

The GeneratorFunction constructor

+ +
+

Note: Arrow function expressions are an experimental technology, part of the ECMAScript 6 proposal, and are not widely supported by browsers yet.

+
+ +
+

Note: GeneratorFunction is not a global object, but could be obtained from generator function instance (see {{jsxref("GeneratorFunction")}} for more detail).

+
+ +
+

Note: Using the GeneratorFunction constructor to create functions is not recommended since it needs the function body as a string which may prevent some JS engine optimizations and can also cause other problems.

+
+ +

As all other objects, {{jsxref("GeneratorFunction")}} objects can be created using the new operator:

+ +
new GeneratorFunction (arg1, arg2, ... argN, functionBody)
+
+ +
+
arg1, arg2, ... argN
+
Zero or more names to be used by the function as formal argument names. Each must be a string that conforms to the rules for a valid JavaScript identifier or a list of such strings separated with a comma; for example "x", "theValue", or "a,b".
+
+ +
+
functionBody
+
A string containing the JavaScript statements comprising the function definition.
+
+ +

Invoking the Function constructor as a function (without using the new operator) has the same effect as invoking it as a constructor.

+ +

Function parameters

+ +
+

Note: Default and rest parameters are experimental technology, part of the ECMAScript 6 proposal, and are not widely supported by browsers yet.

+
+ +

Default parameters

+ +

Default function parameters allow formal parameters to be initialized with default values if no value or undefined is passed. For more details, see default parameters.

+ +

Rest parameters

+ +

The rest parameter syntax allows to represent an indefinite number of arguments as an array. For more details, see rest parameters.

+ +

The arguments object

+ +

You can refer to a function's arguments within the function by using the arguments object. See arguments.

+ + + +

Defining method functions

+ +

Getter and setter functions

+ +

You can define getters (accessor methods) and setters (mutator methods) on any standard built-in object or user-defined object that supports the addition of new properties. The syntax for defining getters and setters uses the object literal syntax.

+ +
+
get
+
+

Binds an object property to a function that will be called when that property is looked up.

+
+
set
+
Binds an object property to a function to be called when there is an attempt to set that property.
+
+ +

Method definition syntax

+ +
+

Note: Method definitions are experimental technology, part of the ECMAScript 6 proposal, and are not widely supported by browsers yet.

+
+ +

Starting with ECMAScript 6, you are able to define own methods in a shorter syntax, similar to the getters and setters. See method definitions for more information.

+ +
var obj = {
+  foo() {},
+  bar() {}
+};
+ +

Function constructor vs. function declaration vs. function expression

+ +

Compare the following:

+ +

A function defined with the Function constructor assigned to the variable multiply:

+ +
function multiply(x, y) {
+   return x * y;
+}
+
+ +

A function expression of an anonymous function assigned to the variable multiply:

+ +
var multiply = function(x, y) {
+   return x * y;
+};
+
+ +

A function expression of a function named func_name assigned to the variable multiply:

+ +
var multiply = function func_name(x, y) {
+   return x * y;
+};
+
+ +

Differences

+ +

All do approximately the same thing, with a few subtle differences:

+ +

There is a distinction between the function name and the variable the function is assigned to. The function name cannot be changed, while the variable the function is assigned to can be reassigned. The function name can be used only within the function's body. Attempting to use it outside the function's body results in an error (or undefined if the function name was previously declared via a var statement). For example:

+ +
var y = function x() {};
+alert(x); // throws an error
+
+ +

The function name also appears when the function is serialized via Function's toString method.

+ +

On the other hand, the variable the function is assigned to is limited only by its scope, which is guaranteed to include the scope where the function is declared in.

+ +

As the 4th example shows, the function name can be different from the variable the function is assigned to. They have no relation to each other.A function declaration also creates a variable with the same name as the function name. Thus, unlike those defined by function expressions, functions defined by function declarations can be accessed by their name in the scope they were defined in:

+ +

A function defined by 'new Function' does not have a function name. However, in the SpiderMonkey JavaScript engine, the serialized form of the function shows as if it has the name "anonymous". For example, alert(new Function()) outputs:

+ +
function anonymous() {
+}
+
+ +

Since the function actually does not have a name, anonymous is not a variable that can be accessed within the function. For example, the following would result in an error:

+ +
var foo = new Function("alert(anonymous);");
+foo();
+
+ +

Unlike functions defined by function expressions or by the Function constructor, a function defined by a function declaration can be used before the function declaration itself. For example:

+ +
foo(); // alerts FOO!
+function foo() {
+   alert('FOO!');
+}
+
+ +

A function defined by a function expression inherits the current scope. That is, the function forms a closure. On the other hand, a function defined by a Function constructor does not inherit any scope other than the global scope (which all functions inherit).

+ +

Functions defined by function expressions and function declarations are parsed only once, while those defined by the Function constructor are not. That is, the function body string passed to the Function constructor must be parsed each and every time the constructor is called. Although a function expression creates a closure every time, the function body is not reparsed, so function expressions are still faster than "new Function(...)". Therefore the Function constructor should generally be avoided whenever possible.

+ +

It should be noted, however, that function expressions and function declarations nested within the function generated by parsing a Function constructor 's string aren't parsed repeatedly. For example:

+ +
var foo = (new Function("var bar = \'FOO!\';\nreturn(function() {\n\talert(bar);\n});"))();
+foo(); // The segment "function() {\n\talert(bar);\n}" of the function body string is not re-parsed.
+ +

A function declaration is very easily (and often unintentionally) turned into a function expression. A function declaration ceases to be one when it either:

+ + + +
var x = 0;               // source element
+if (x == 0) {            // source element
+   x = 10;               // not a source element
+   function boo() {}     // not a source element
+}
+function foo() {         // source element
+   var y = 20;           // source element
+   function bar() {}     // source element
+   while (y == 10) {     // source element
+      function blah() {} // not a source element
+      y++;               // not a source element
+   }
+}
+
+ +

Examples

+ +
// function declaration
+function foo() {}
+
+// function expression
+(function bar() {})
+
+// function expression
+x = function hello() {}
+
+
+if (x) {
+   // function expression
+   function world() {}
+}
+
+
+// function declaration
+function a() {
+   // function declaration
+   function b() {}
+   if (0) {
+      // function expression
+      function c() {}
+   }
+}
+
+ +

Block-level functions

+ +

In strict mode, starting with ES2015 (ES6), functions inside blocks are now scoped to that block. Prior to ES6, block-level functions were forbidden in strict mode.

+ +
'use strict';
+
+function f() {
+  return 1;
+}
+
+{
+  function f() {
+    return 2;
+  }
+}
+
+f() === 1; // true
+
+// f() === 2 in non-strict mode
+
+ +

Block-level functions in non-strict code

+ +

In a word: Don't.

+ +

In non-strict code, function declarations inside blocks behave strangely. For example:

+ +
if (shouldDefineZero) {
+   function zero() {     // DANGER: compatibility risk
+      console.log("This is zero.");
+   }
+}
+
+ +

ES2015 says that if shouldDefineZero is false, then zero should never be defined, since the block never executes. However, it's a new part of the standard. Historically, this was left unspecified, and some browsers would define zero whether the block executed or not.

+ +

In strict mode, all browsers that support ES2015 handle this the same way: zero is defined only if shouldDefineZero is true, and only in the scope of the if-block.

+ +

A safer way to define functions conditionally is to assign a function expression to a variable:

+ +
var zero;
+if (0) {
+   zero = function() {
+      console.log("This is zero.");
+   };
+}
+
+ +

Examples

+ +

Returning a formatted number

+ +

The following function returns a string containing the formatted representation of a number padded with leading zeros.

+ +
// This function returns a string padded with leading zeros
+function padZeros(num, totalLen) {
+   var numStr = num.toString();             // Initialize return value as string
+   var numZeros = totalLen - numStr.length; // Calculate no. of zeros
+   for (var i = 1; i <= numZeros; i++) {
+      numStr = "0" + numStr;
+   }
+   return numStr;
+}
+
+ +

The following statements call the padZeros function.

+ +
var result;
+result = padZeros(42,4); // returns "0042"
+result = padZeros(42,2); // returns "42"
+result = padZeros(5,4);  // returns "0005"
+
+ +

Determining whether a function exists

+ +

You can determine whether a function exists by using the typeof operator. In the following example, a test is peformed to determine if the window object has a property called noFunc that is a function. If so, it is used; otherwise some other action is taken.

+ +
 if ('function' == typeof window.noFunc) {
+   // use noFunc()
+ } else {
+   // do something else
+ }
+
+ +

Note that in the if test, a reference to noFunc is used—there are no brackets "()" after the function name so the actual function is not called.

+ +

Specifications

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('ES1')}}{{Spec2('ES1')}}Initial definition. Implemented in JavaScript 1.0
{{SpecName('ES5.1', '#sec-13', 'Function Definition')}}{{Spec2('ES5.1')}} 
{{SpecName('ES6', '#sec-function-definitions', 'Function definitions')}}{{Spec2('ES6')}}New: Arrow functions, Generator functions, default parameters, rest parameters.
{{SpecName('ESDraft', '#sec-function-definitions', 'Function definitions')}}{{Spec2('ESDraft')}} 
+ +

Browser compatibility

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
Generator functions39{{CompatGeckoDesktop("26.0")}}{{CompatUnknown}}26{{CompatUnknown}}
Arrow functions{{CompatNo}}{{CompatGeckoDesktop("22.0")}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
Block-level functions{{CompatUnknown}}{{CompatGeckoDesktop("46.0")}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
Generator functions{{CompatUnknown}}39{{CompatGeckoMobile("26.0")}}{{CompatUnknown}}26{{CompatUnknown}}
Arrow functions{{CompatNo}}{{CompatNo}}{{CompatGeckoMobile("22.0")}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
Block-level functions{{CompatUnknown}}{{CompatUnknown}}{{CompatGeckoMobile("46.0")}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
+
+ +

See also

+ + diff --git a/files/ar/web/javascript/reference/global_objects/number/index.html b/files/ar/web/javascript/reference/global_objects/number/index.html new file mode 100644 index 0000000000..cb667fd3d8 --- /dev/null +++ b/files/ar/web/javascript/reference/global_objects/number/index.html @@ -0,0 +1,12 @@ +--- +title: الارقام في الجافا سكربت +slug: Web/JavaScript/Reference/Global_Objects/الارقام +translation_of: Web/JavaScript/Reference/Global_Objects/Number +--- +

 وهو كائن غلاف يستخدم لتمثيل ومعالجة الأرقام مثل  37  او 9.25 Numberمنشئ يحتوي على الثوابت وطرق للعمل مع الأرقام. يمكن تحويل قيم الأنواع الأخرى إلى أرقام باستخدام Number()الوظيفة.

+ +

جافا سكريبت رقم نوع عبارة عن قيمة مزدوجة الدقة بتنسيق IEEE 754 تنسيق ثنائي 64 بت ذات ، كما هو الحال doubleفي Java أو C #. هذا يعني أنه يمكن أن يمثل قيمًا كسرية ، ولكن هناك بعض الحدود لما يمكن تخزينه. يحتفظ فقط بحوالي   17 رقم  منزلاً عشريًا من الدقة ؛ الحساب يخضع للتقريب . أكبر قيمة يمكن أن يحملها رقم هي حوالي 1.8 × 10 308 . يتم استبدال الأعداد التي تتجاوز ذلك بثابت الرقم الخاص Infinity.

+ +

الرقم الحرفي مثل 37كود JavaScript هو قيمة فاصلة عائمة ، وليس عددًا صحيحًا. لا يوجد نوع عدد صحيح منفصل في الاستخدام اليومي الشائع. (يحتوي JavaScript الآن على BigIntنوع ، لكنه لم يتم تصميمه ليحل محل Number للاستخدامات اليومية. 37لا يزال رقمًا ، وليس BigInt.)

+ +

يمكن أيضًا التعبير عن الرقم بأشكال حرفية مثل 0b101، 0o13، 0x0A. تعرف على المزيد حول العددي قواعد المعجم هنا .

diff --git "a/files/ar/web/javascript/reference/global_objects/\330\247\331\204\330\247\330\261\331\202\330\247\331\205/index.html" "b/files/ar/web/javascript/reference/global_objects/\330\247\331\204\330\247\330\261\331\202\330\247\331\205/index.html" deleted file mode 100644 index cb667fd3d8..0000000000 --- "a/files/ar/web/javascript/reference/global_objects/\330\247\331\204\330\247\330\261\331\202\330\247\331\205/index.html" +++ /dev/null @@ -1,12 +0,0 @@ ---- -title: الارقام في الجافا سكربت -slug: Web/JavaScript/Reference/Global_Objects/الارقام -translation_of: Web/JavaScript/Reference/Global_Objects/Number ---- -

 وهو كائن غلاف يستخدم لتمثيل ومعالجة الأرقام مثل  37  او 9.25 Numberمنشئ يحتوي على الثوابت وطرق للعمل مع الأرقام. يمكن تحويل قيم الأنواع الأخرى إلى أرقام باستخدام Number()الوظيفة.

- -

جافا سكريبت رقم نوع عبارة عن قيمة مزدوجة الدقة بتنسيق IEEE 754 تنسيق ثنائي 64 بت ذات ، كما هو الحال doubleفي Java أو C #. هذا يعني أنه يمكن أن يمثل قيمًا كسرية ، ولكن هناك بعض الحدود لما يمكن تخزينه. يحتفظ فقط بحوالي   17 رقم  منزلاً عشريًا من الدقة ؛ الحساب يخضع للتقريب . أكبر قيمة يمكن أن يحملها رقم هي حوالي 1.8 × 10 308 . يتم استبدال الأعداد التي تتجاوز ذلك بثابت الرقم الخاص Infinity.

- -

الرقم الحرفي مثل 37كود JavaScript هو قيمة فاصلة عائمة ، وليس عددًا صحيحًا. لا يوجد نوع عدد صحيح منفصل في الاستخدام اليومي الشائع. (يحتوي JavaScript الآن على BigIntنوع ، لكنه لم يتم تصميمه ليحل محل Number للاستخدامات اليومية. 37لا يزال رقمًا ، وليس BigInt.)

- -

يمكن أيضًا التعبير عن الرقم بأشكال حرفية مثل 0b101، 0o13، 0x0A. تعرف على المزيد حول العددي قواعد المعجم هنا .

diff --git "a/files/ar/web/javascript/reference/\330\247\331\204\330\257\331\210\330\247\331\204/get/index.html" "b/files/ar/web/javascript/reference/\330\247\331\204\330\257\331\210\330\247\331\204/get/index.html" deleted file mode 100644 index d3789ba7bd..0000000000 --- "a/files/ar/web/javascript/reference/\330\247\331\204\330\257\331\210\330\247\331\204/get/index.html" +++ /dev/null @@ -1,165 +0,0 @@ ---- -title: getter -slug: Web/JavaScript/Reference/الدوال/get -translation_of: Web/JavaScript/Reference/Functions/get ---- -
{{jsSidebar("Functions")}}
- -

The get صينطاكس طعمنيققbinds an object property to a function that will be called when that property is looked up.

- -
{{EmbedInteractiveExample("pages/js/functions-getter.html")}}
- - - -

Syntax

- -
{get prop() { ... } }
-{get [expression]() { ... } }
- -

Parameters

- -
-
prop
-
rty to bind to the given fun-tion.
-
expression
-
Starting with ECMAScript 2015, you can also use expressions for a computed property name to bind to the given function.
-
- -

Description

- -

احا الشبشب ضاع احا دا كان ةبصباع

- -

It is not possible to simultaneously have a getter bound to a property and have that property actually hold a value, although it is possible to use a getter and a setter in conjunction to create a type of pseudo-property.

- -

Note the following when working with the get syntax:

- - - -

Examples

- -

Defining a getter on new objects in object initializers

- -

This will create a pseudo-property latest for object obj, which will return the last array item in log.

- -
const obj = {
-  log: ['example','test'],
-  get latest() {
-    if (this.log.length === 0) return undefined;
-    return this.log[this.log.length - 1];
-  }
-}
-console.log(obj.latest); // "test"
-
- -

Note that attempting to assign a value to latest will not change it.

- -

Deleting a getter using the delete operator

- -

If you want to remove the getter, you can just {{jsxref("Operators/delete", "delete")}} it:

- -
delete obj.latest;
-
- -

Defining a getter on existing objects using defineProperty

- -

To append a getter to an existing object later at any time, use {{jsxref("Object.defineProperty()")}}.

- -
const o = {a: 0};
-
-Object.defineProperty(o, 'b', { get: function() { return this.a + 1; } });
-
-console.log(o.b) // Runs the getter, which yields a + 1 (which is 1)
- -

Using a computed property name

- -
const expr = 'foo';
-
-const obj = {
-  get [expr]() { return 'bar'; }
-};
-
-console.log(obj.foo); // "bar"
- -

Smart / self-overwriting / lazy getters

- -

Getters give you a way to define a property of an object, but they do not calculate the property's value until it is accessed. A getter defers the cost of calculating the value until the value is needed. If it is never needed, you never pay the cost.

- -

An additional optimization technique to lazify or delay the calculation of a property value and cache it for later access are smart (or "memoized") getters. The value is calculated the first time the getter is called, and is then cached so subsequent accesses return the cached value without recalculating it. This is useful in the following situations:

- - - -
-

This means that you shouldn’t write a lazy getter for a property whose value you expect to change, because if the getter is lazy then it will not recalculate the value.

- -

Note that getters are not “lazy” or “memozied” by nature; you must implement this technique if you desire this behavior.

-
- -

In the following example, the object has a getter as its own property. On getting the property, the property is removed from the object and re-added, but implicitly as a data property this time. Finally, the value getsreturn this.notifier = document.getElementById('bookmarked-notification-anchor'); },

- -

For Firefox code, see also the XPCOMUtils.jsm code module, which defines the defineLazyGetter() function.

- -

get vs. defineProperty

- -

While using the get keyword and {{jsxref("Object.defineProperty()")}} have similar results, there is a subtle difference between the two when used on {{jsxref("classes")}}.

- -

When using get the property will be defined on the instance's prototype, while using {{jsxref("Object.defineProperty()")}} the property will be defined on the instance it is applied to.

- -
class Example {
-  get hello() {
-    return 'world';
-  }
-}
-
-const obj = new Example();
-console.log(obj.hello);
-// "world"
-
-console.log(Object.getOwnPropertyDescriptor(obj, 'hello'));
-// undefined
-
-console.log(
-  Object.getOwnPropertyDescriptor(
-    Object.getPrototypeOf(obj), 'hello'
-  )
-);
-// { configurable: true, enumerable: false, get: function get hello() { return 'world'; }, set: undefined }
- -

Specifications

- - - - - - - - - - - - -
Specification
{{SpecName('ESDraft', '#sec-method-definitions', 'Method definitions')}}
- -

Browser compatibility

- - - -

{{Compat("javascript.functions.get")}}

- -

See also

- - diff --git "a/files/ar/web/javascript/reference/\330\247\331\204\330\257\331\210\330\247\331\204/index.html" "b/files/ar/web/javascript/reference/\330\247\331\204\330\257\331\210\330\247\331\204/index.html" deleted file mode 100644 index 368d8af03d..0000000000 --- "a/files/ar/web/javascript/reference/\330\247\331\204\330\257\331\210\330\247\331\204/index.html" +++ /dev/null @@ -1,645 +0,0 @@ ---- -title: الدوال -slug: Web/JavaScript/Reference/الدوال -translation_of: Web/JavaScript/Reference/Functions ---- -
{{jsSidebar("Functions")}}
- -

Generally speaking, a function is a "subprogram" that can be called by code external (or internal in the case of recursion) to the function. Like the program itself, a function is composed of a sequence of statements called the function body. Values can be passed to a function, and the function will return a value.

- -

In JavaScript, functions are first-class objects, because they can have properties and methods just like any other object. What distinguishes them from other objects is that functions can be called. In brief, they are Function objects.

- -

For more examples and explanations, see also the JavaScript guide about functions.

- -

Description

- -

Every function in JavaScript is a Function object. See {{jsxref("Function")}} for information on properties and methods of Function objects.

- -

Functions are not the same as procedures. A function always returns a value, whereas a procedure might not.

- -

To return a value other than the default, a function must have a return statement that specifies the value to return. A function without a return statement will return a default value. In the case of a constructor called with the new keyword, the default value is the value of its this parameter. For all other functions, the default return value is undefined.

- -

The parameters of a function call are the function's arguments. Arguments are passed to functions by value. If the function changes the value of an argument, this change is not reflected globally or in the calling function. However, object references are values, too, and they are special: if the function changes the referred object's properties, that change is visible outside the function, as shown in the following example:

- -
/* Declare the function 'myFunc' */
-function myFunc(theObject) {
-   theObject.brand = "Toyota";
- }
-
- /*
-  * Declare variable 'mycar';
-  * create and initialize a new Object;
-  * assign reference to it to 'mycar'
-  */
- var mycar = {
-   brand: "Honda",
-   model: "Accord",
-   year: 1998
- };
-
- /* Logs 'Honda' */
- console.log(mycar.brand);
-
- /* Pass object reference to the function */
- myFunc(mycar);
-
- /*
-  * Logs 'Toyota' as the value of the 'brand' property
-  * of the object, as changed to by the function.
-  */
- console.log(mycar.brand);
-
- -

The this keyword does not refer to the currently executing function, so you must refer to Function objects by name, even within the function body.

- -

Defining functions

- -

There are several ways to define functions:

- -

The function declaration (function statement)

- -

There is a special syntax for declaring functions (see function statement for details):

- -
function name([param[, param[, ... param]]]) {
-   statements
-}
-
- -
-
name
-
The function name.
-
- -
-
param
-
The name of an argument to be passed to the function. A function can have up to 255 arguments.
-
- -
-
statements
-
The statements comprising the body of the function.
-
- -

The function expression (function expression)

- -

A function expression is similar to and has the same syntax as a function declaration (see function expression for details):

- -
function [name]([param[, param[, ... param]]]) {
-   statements
-}
-
- -
-
name
-
The function name. Can be omitted, in which case the function becomes known as an anonymous function.
-
- -
-
param
-
The name of an argument to be passed to the function. A function can have up to 255 arguments.
-
statements
-
The statements comprising the body of the function.
-
- -

The generator function declaration (function* statement)

- -
-

Note: Generator functions are an experimental technology, part of the ECMAScript 6 proposal, and are not widely supported by browsers yet.

-
- -

There is a special syntax for generator function declarations (see {{jsxref('Statements/function*', 'function* statement')}} for details):

- -
function* name([param[, param[, ... param]]]) {
-   statements
-}
-
- -
-
name
-
The function name.
-
- -
-
param
-
The name of an argument to be passed to the function. A function can have up to 255 arguments.
-
- -
-
statements
-
The statements comprising the body of the function.
-
- -

The generator function expression (function* expression)

- -
-

Note: Generator functions are an experimental technology, part of the ECMAScript 6 proposal, and are not widely supported by browsers yet.

-
- -

A generator function expression is similar to and has the same syntax as a generator function declaration (see {{jsxref('Operators/function*', 'function* expression')}} for details):

- -
function* [name]([param[, param[, ... param]]]) {
-   statements
-}
-
- -
-
name
-
The function name. Can be omitted, in which case the function becomes known as an anonymous function.
-
- -
-
param
-
The name of an argument to be passed to the function. A function can have up to 255 arguments.
-
statements
-
The statements comprising the body of the function.
-
- -

The arrow function expression (=>)

- -
-

Note: Arrow function expressions are an experimental technology, part of the ECMAScript 6 proposal, and are not widely supported by browsers yet.

-
- -

An arrow function expression has a shorter syntax and lexically binds its this value (see arrow functions for details):

- -
([param[, param]]) => {
-   statements
-}
-
-param => expression
-
- -
-
param
-
The name of an argument. Zero arguments need to be indicated with ().  For only one argument, the parentheses are not required. (like foo => 1)
-
statements or expression
-
Multiple statements need to be enclosed in brackets. A single expression requires no brackets. The expression is also the implicit return value of the function.
-
- -

The Function constructor

- -
-

Note: Using the Function constructor to create functions is not recommended since it needs the function body as a string which may prevent some JS engine optimizations and can also cause other problems.

-
- -

As all other objects, {{jsxref("Function")}} objects can be created using the new operator:

- -
new Function (arg1, arg2, ... argN, functionBody)
-
- -
-
arg1, arg2, ... argN
-
Zero or more names to be used by the function as formal parameters. Each must be a proper JavaScript identifier.
-
- -
-
functionBody
-
A string containing the JavaScript statements comprising the function body.
-
- -

Invoking the Function constructor as a function (without using the new operator) has the same effect as invoking it as a constructor.

- -

The GeneratorFunction constructor

- -
-

Note: Arrow function expressions are an experimental technology, part of the ECMAScript 6 proposal, and are not widely supported by browsers yet.

-
- -
-

Note: GeneratorFunction is not a global object, but could be obtained from generator function instance (see {{jsxref("GeneratorFunction")}} for more detail).

-
- -
-

Note: Using the GeneratorFunction constructor to create functions is not recommended since it needs the function body as a string which may prevent some JS engine optimizations and can also cause other problems.

-
- -

As all other objects, {{jsxref("GeneratorFunction")}} objects can be created using the new operator:

- -
new GeneratorFunction (arg1, arg2, ... argN, functionBody)
-
- -
-
arg1, arg2, ... argN
-
Zero or more names to be used by the function as formal argument names. Each must be a string that conforms to the rules for a valid JavaScript identifier or a list of such strings separated with a comma; for example "x", "theValue", or "a,b".
-
- -
-
functionBody
-
A string containing the JavaScript statements comprising the function definition.
-
- -

Invoking the Function constructor as a function (without using the new operator) has the same effect as invoking it as a constructor.

- -

Function parameters

- -
-

Note: Default and rest parameters are experimental technology, part of the ECMAScript 6 proposal, and are not widely supported by browsers yet.

-
- -

Default parameters

- -

Default function parameters allow formal parameters to be initialized with default values if no value or undefined is passed. For more details, see default parameters.

- -

Rest parameters

- -

The rest parameter syntax allows to represent an indefinite number of arguments as an array. For more details, see rest parameters.

- -

The arguments object

- -

You can refer to a function's arguments within the function by using the arguments object. See arguments.

- - - -

Defining method functions

- -

Getter and setter functions

- -

You can define getters (accessor methods) and setters (mutator methods) on any standard built-in object or user-defined object that supports the addition of new properties. The syntax for defining getters and setters uses the object literal syntax.

- -
-
get
-
-

Binds an object property to a function that will be called when that property is looked up.

-
-
set
-
Binds an object property to a function to be called when there is an attempt to set that property.
-
- -

Method definition syntax

- -
-

Note: Method definitions are experimental technology, part of the ECMAScript 6 proposal, and are not widely supported by browsers yet.

-
- -

Starting with ECMAScript 6, you are able to define own methods in a shorter syntax, similar to the getters and setters. See method definitions for more information.

- -
var obj = {
-  foo() {},
-  bar() {}
-};
- -

Function constructor vs. function declaration vs. function expression

- -

Compare the following:

- -

A function defined with the Function constructor assigned to the variable multiply:

- -
function multiply(x, y) {
-   return x * y;
-}
-
- -

A function expression of an anonymous function assigned to the variable multiply:

- -
var multiply = function(x, y) {
-   return x * y;
-};
-
- -

A function expression of a function named func_name assigned to the variable multiply:

- -
var multiply = function func_name(x, y) {
-   return x * y;
-};
-
- -

Differences

- -

All do approximately the same thing, with a few subtle differences:

- -

There is a distinction between the function name and the variable the function is assigned to. The function name cannot be changed, while the variable the function is assigned to can be reassigned. The function name can be used only within the function's body. Attempting to use it outside the function's body results in an error (or undefined if the function name was previously declared via a var statement). For example:

- -
var y = function x() {};
-alert(x); // throws an error
-
- -

The function name also appears when the function is serialized via Function's toString method.

- -

On the other hand, the variable the function is assigned to is limited only by its scope, which is guaranteed to include the scope where the function is declared in.

- -

As the 4th example shows, the function name can be different from the variable the function is assigned to. They have no relation to each other.A function declaration also creates a variable with the same name as the function name. Thus, unlike those defined by function expressions, functions defined by function declarations can be accessed by their name in the scope they were defined in:

- -

A function defined by 'new Function' does not have a function name. However, in the SpiderMonkey JavaScript engine, the serialized form of the function shows as if it has the name "anonymous". For example, alert(new Function()) outputs:

- -
function anonymous() {
-}
-
- -

Since the function actually does not have a name, anonymous is not a variable that can be accessed within the function. For example, the following would result in an error:

- -
var foo = new Function("alert(anonymous);");
-foo();
-
- -

Unlike functions defined by function expressions or by the Function constructor, a function defined by a function declaration can be used before the function declaration itself. For example:

- -
foo(); // alerts FOO!
-function foo() {
-   alert('FOO!');
-}
-
- -

A function defined by a function expression inherits the current scope. That is, the function forms a closure. On the other hand, a function defined by a Function constructor does not inherit any scope other than the global scope (which all functions inherit).

- -

Functions defined by function expressions and function declarations are parsed only once, while those defined by the Function constructor are not. That is, the function body string passed to the Function constructor must be parsed each and every time the constructor is called. Although a function expression creates a closure every time, the function body is not reparsed, so function expressions are still faster than "new Function(...)". Therefore the Function constructor should generally be avoided whenever possible.

- -

It should be noted, however, that function expressions and function declarations nested within the function generated by parsing a Function constructor 's string aren't parsed repeatedly. For example:

- -
var foo = (new Function("var bar = \'FOO!\';\nreturn(function() {\n\talert(bar);\n});"))();
-foo(); // The segment "function() {\n\talert(bar);\n}" of the function body string is not re-parsed.
- -

A function declaration is very easily (and often unintentionally) turned into a function expression. A function declaration ceases to be one when it either:

- - - -
var x = 0;               // source element
-if (x == 0) {            // source element
-   x = 10;               // not a source element
-   function boo() {}     // not a source element
-}
-function foo() {         // source element
-   var y = 20;           // source element
-   function bar() {}     // source element
-   while (y == 10) {     // source element
-      function blah() {} // not a source element
-      y++;               // not a source element
-   }
-}
-
- -

Examples

- -
// function declaration
-function foo() {}
-
-// function expression
-(function bar() {})
-
-// function expression
-x = function hello() {}
-
-
-if (x) {
-   // function expression
-   function world() {}
-}
-
-
-// function declaration
-function a() {
-   // function declaration
-   function b() {}
-   if (0) {
-      // function expression
-      function c() {}
-   }
-}
-
- -

Block-level functions

- -

In strict mode, starting with ES2015 (ES6), functions inside blocks are now scoped to that block. Prior to ES6, block-level functions were forbidden in strict mode.

- -
'use strict';
-
-function f() {
-  return 1;
-}
-
-{
-  function f() {
-    return 2;
-  }
-}
-
-f() === 1; // true
-
-// f() === 2 in non-strict mode
-
- -

Block-level functions in non-strict code

- -

In a word: Don't.

- -

In non-strict code, function declarations inside blocks behave strangely. For example:

- -
if (shouldDefineZero) {
-   function zero() {     // DANGER: compatibility risk
-      console.log("This is zero.");
-   }
-}
-
- -

ES2015 says that if shouldDefineZero is false, then zero should never be defined, since the block never executes. However, it's a new part of the standard. Historically, this was left unspecified, and some browsers would define zero whether the block executed or not.

- -

In strict mode, all browsers that support ES2015 handle this the same way: zero is defined only if shouldDefineZero is true, and only in the scope of the if-block.

- -

A safer way to define functions conditionally is to assign a function expression to a variable:

- -
var zero;
-if (0) {
-   zero = function() {
-      console.log("This is zero.");
-   };
-}
-
- -

Examples

- -

Returning a formatted number

- -

The following function returns a string containing the formatted representation of a number padded with leading zeros.

- -
// This function returns a string padded with leading zeros
-function padZeros(num, totalLen) {
-   var numStr = num.toString();             // Initialize return value as string
-   var numZeros = totalLen - numStr.length; // Calculate no. of zeros
-   for (var i = 1; i <= numZeros; i++) {
-      numStr = "0" + numStr;
-   }
-   return numStr;
-}
-
- -

The following statements call the padZeros function.

- -
var result;
-result = padZeros(42,4); // returns "0042"
-result = padZeros(42,2); // returns "42"
-result = padZeros(5,4);  // returns "0005"
-
- -

Determining whether a function exists

- -

You can determine whether a function exists by using the typeof operator. In the following example, a test is peformed to determine if the window object has a property called noFunc that is a function. If so, it is used; otherwise some other action is taken.

- -
 if ('function' == typeof window.noFunc) {
-   // use noFunc()
- } else {
-   // do something else
- }
-
- -

Note that in the if test, a reference to noFunc is used—there are no brackets "()" after the function name so the actual function is not called.

- -

Specifications

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SpecificationStatusComment
{{SpecName('ES1')}}{{Spec2('ES1')}}Initial definition. Implemented in JavaScript 1.0
{{SpecName('ES5.1', '#sec-13', 'Function Definition')}}{{Spec2('ES5.1')}} 
{{SpecName('ES6', '#sec-function-definitions', 'Function definitions')}}{{Spec2('ES6')}}New: Arrow functions, Generator functions, default parameters, rest parameters.
{{SpecName('ESDraft', '#sec-function-definitions', 'Function definitions')}}{{Spec2('ESDraft')}} 
- -

Browser compatibility

- -

{{CompatibilityTable}}

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
Generator functions39{{CompatGeckoDesktop("26.0")}}{{CompatUnknown}}26{{CompatUnknown}}
Arrow functions{{CompatNo}}{{CompatGeckoDesktop("22.0")}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
Block-level functions{{CompatUnknown}}{{CompatGeckoDesktop("46.0")}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}{{CompatVersionUnknown}}
Generator functions{{CompatUnknown}}39{{CompatGeckoMobile("26.0")}}{{CompatUnknown}}26{{CompatUnknown}}
Arrow functions{{CompatNo}}{{CompatNo}}{{CompatGeckoMobile("22.0")}}{{CompatNo}}{{CompatNo}}{{CompatNo}}
Block-level functions{{CompatUnknown}}{{CompatUnknown}}{{CompatGeckoMobile("46.0")}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
-
- -

See also

- - -- cgit v1.2.3-54-g00ecf