From 4b1a9203c547c019fc5398082ae19a3f3d4c3efe Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 8 Dec 2020 14:41:15 -0500 Subject: initial commit --- .../control_flow_and_error_handling/index.html | 467 ++++++++++++ .../javascript/guide/grammar_and_types/index.html | 680 +++++++++++++++++ files/ar/web/javascript/guide/index.html | 116 +++ .../web/javascript/guide/introduction/index.html | 159 ++++ .../guide/loops_and_iteration/index.html | 352 +++++++++ .../guide/regular_expressions/index.html | 813 +++++++++++++++++++++ .../guide/working_with_objects/index.html | 516 +++++++++++++ .../index.html" | 698 ++++++++++++++++++ 8 files changed, 3801 insertions(+) create mode 100644 files/ar/web/javascript/guide/control_flow_and_error_handling/index.html create mode 100644 files/ar/web/javascript/guide/grammar_and_types/index.html create mode 100644 files/ar/web/javascript/guide/index.html create mode 100644 files/ar/web/javascript/guide/introduction/index.html create mode 100644 files/ar/web/javascript/guide/loops_and_iteration/index.html create mode 100644 files/ar/web/javascript/guide/regular_expressions/index.html create mode 100644 files/ar/web/javascript/guide/working_with_objects/index.html create mode 100644 "files/ar/web/javascript/guide/\330\247\331\204\330\257\331\210\330\247\331\204/index.html" (limited to 'files/ar/web/javascript/guide') diff --git a/files/ar/web/javascript/guide/control_flow_and_error_handling/index.html b/files/ar/web/javascript/guide/control_flow_and_error_handling/index.html new file mode 100644 index 0000000000..d87ef2f7e9 --- /dev/null +++ b/files/ar/web/javascript/guide/control_flow_and_error_handling/index.html @@ -0,0 +1,467 @@ +--- +title: التحكم فى التدفق وامساك الاخطاء +slug: Web/JavaScript/Guide/Control_flow_and_error_handling +translation_of: Web/JavaScript/Guide/Control_flow_and_error_handling +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Grammar_and_types", "Web/JavaScript/Guide/Loops_and_iteration")}}
+ +

جافاسكريبت تدعم مجموعة من البيانات المدمجة، وتحديدا التحكم في تدفق البيانات، التي يمكنك استخدامها لخلق قدرا كبيرا من التفاعل في التطبيق الخاص بك. يقدم هذا الفصل لمحة عامة عن هذه البيانات.

+ +
+

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

+ +
+

ملحوظة: برامج الجافاسكريبت وبيانات الجافاسكريبت، غالباً ما تسمى تعليمات برمجية.

+
+ +

أي تعبير جافا سكريبت، هو  أيضا تعليمة برمجية. راجع Expressions and operators  للحصول على معلومات كاملة حول التعبيرات.

+ +

Block statement

+ +

ابسط تعليمة برمجية هي التعليمة البرمجية بلوك  block، التي تستخدم لاحتواء مجموعة من التعليمات البرمجية. البلوك محدد بواسطة الاقواس المتعرجة:

+ +
{
+  statement_1;
+  statement_2;
+  .
+  .
+  .
+  statement_n;
+}
+
+ +

مثال

+ +

اغلب استخدامات البلوك، تكون مع تعليمات التحكم في التدفق ( مثل if, for, while )

+ +
while (x < 10) {
+  x++;
+}
+
+ +

لدينا هنا، { ;++x } التعليمة البرمجة block.

+ +

هام: في جافا سكريبت قبل ECMAScript2015. البلوك لم يكن لديه نطاق. المتغيرات المستخدمة في البلوك، سيتم تغيير نطاقها الى النطاق العام وهو السكريبت، فتصبح متغيرات عامة متاحة لجميع التعليمات البرمجية في السكريبت، اما اذا وجد البلوك داخل دالة سيتم تغيير نطاقها لهذه الدالة، وبالتالي ستصبح متغيرات محلية متاحة لهذه الدالة فقط.

+ +

في جافا سكريبت، البلوكات "المستقلة"  يمكن أن ينتج  عنها نتائج مختلفة تماما عما كان سينتج في C أو جافا. فمثلا

+ +
var x = 1;
+{
+  var x = 2;
+}
+console.log(x); // outputs 2
+
+ +

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

+ +

ابتداءا من ECMAScript2015. استخدام المتغير let داخل البلوك سينتج عنه سلوك مغاير. راجع {{jsxref("Statements/let", "let")}} صفحة المرجع للحصول على مزيد من المعلومات.

+ +

التعليمات الشرطية

+ +

التعليمة الشرطية هي مجموعة من الأوامر التي ستنفذ إذا تحقق شرطا معيناً. تدعم الجافاسكريبت اثنين من التعليمات الشرطية: هما if...else و switch.

+ +

التعليمة if...else

+ +

ستنفذ التعليمة البرمجية المرتبطة بالتعليمة if اذا كان الشرط المنطقي يساوي true. وكذالك ستنفذ التعليمة البرمجية المرتبطة بالتعليمة else اذا كان الشرط المنطقي يساوي false. استخدام التعليمة else اختياري. فيما تكون التعليمة if على الشكل التالي،

+ +
if (condition) {
+  statement_1;
+} else {
+  statement_2;
+}
+ +

الشرط condition، يمكن ان يكون اي تعبير لإختبار ما اذا كان الشرط true او false راجع Boolean. لتوضيح ما الذي سيتم تنفيذه: في حالة ما اذا كان الشرط صحيح  سيتم تنفيذ statement_1، اما اذا كان الشرط غير صحيح سيتم تنفيذ statement_2، يمكن ل statement_1 و statement_2 ان تكون اي تعليمات برمجية، بما فيها تعليمة if اخرى.

+ +

يمكنك أيضا توسيع مجال التعليمات الشرطية باستخدام else if لاختبار شروط متعددة في تسلسل، كما يلي:

+ +
if (condition_1) {
+  statement_1;
+} else if (condition_2) {
+  statement_2;
+} else if (condition_n) {
+  statement_n;
+} else {
+  statement_last;
+}
+
+
+ +

في حالة وجود شروط متعددة سيتم تنفيذ شرط واحد فقط، وهو الشرط المنطقي الذي سيتم اختباره ب true. لتنفيذ عدة تعليمات برمجية، قم بتضمينها في التعليمة بلوك ({ ... }). من الجيد دائماً استخدام التعليمة بلوك، لا سيما عند استخدام التعليمات الشرطية المتداخلة :

+ +
if (condition) {
+  statement_1_runs_if_condition_is_true;
+  statement_2_runs_if_condition_is_true;
+} else {
+  statement_3_runs_if_condition_is_false;
+  statement_4_runs_if_condition_is_false;
+}
+
+ +
من المستحسن عدم استخدام التعيينات البسيطة في التعبير الشرطي، لأنه يمكن الخلط بين التعيين والمساواة، على سبيل المثال، لا تستخدم التالي:
+ +
 
+ +
if (x = y) {
+  /* statements here */
+}
+
+ +

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

+ +
if ((x = y)) {
+  /* statements here */
+}
+
+ +

القيم  Falsy

+ +

القيم التالية تُقَيًم إلى false عند اختباها في تعليمة شرطية (وتعرف ايضا بالقيم {{Glossary("Falsy")}}):

+ + + +

كل القيم الأخرى، بما في ذلك جميع الكائنات، تقيم إلى true عندما يتم تمريرها إلى تعليمة شرطية.

+ +

لا تخلط بين القيم المنطقية الاولية true و false مع القيم true و false للكائن {{jsxref("Boolean")}}. على سبيل المثال:

+ +
var b = new Boolean(false);
+if (b) // this condition evaluates to true
+if (b == true) // this condition evaluates to false
+
+ +

مثال

+ +

فى المثال التالى, الدالة checkData ستعود ب true ادا كان عدد الحروف في الكائن Text يساوي ثلاثة، بخلاف ذالك، سيظهر التنبيه (alert) وتعود ب false.

+ +
function checkData() {
+  if (document.form1.threeChar.value.length == 3) {
+    return true;
+  } else {
+    alert('Enter exactly three characters. ' +
+    document.form1.threeChar.value + ' is not valid.');
+    return false;
+  }
+}
+
+ +

التعليمة switch

+ +

التعليمة switch تسمح للبرنامج باختبار التعبير، وذالك من خلال مطابقة قيمة التعبير مع الحالة case. إذا تم العثور على تطابق، البرنامج سينفذ التعليمة البرمجية المرتبطة بها. التعليمة switch تكون على الشكل التالي:

+ +
switch (expression) {
+  case label_1:
+    statements_1
+    [break;]
+  case label_2:
+    statements_2
+    [break;]
+    ...
+  default:
+    statements_def
+    [break;]
+}
+
+ +

بداية يقوم البرنامج بالبحث عن الحالة case التي تطابق قيمتها قيمة ال expression، اذا وجدت، يقوم البرنامج بتنفيذ التعليمة البرمجية المرتبطة بها، اذا لم يجد ما يبحث عنه في اي من الحالات case، سيقوم البرنامج بتنفيذ التعليمات البرمجية المرتبطة بالحالة default اذا وجدت، لان وجود الحالة default في التعليمة switch اختياري. اذا لم يجد البرنامج اي حالة case متطابقة ولا الحالة default سيقوم بتنفيذ التعليمات البرمجية التي تلي التعليمة switch.

+ +

التعليمة break مرتبطة مع كل حالة case، مهمتها جعل البرنامج يقفز خارج التعليمة switch بمجرد تنفيذ التعليمة البرمجية، واستكمال تنفيذ التعليمات البرمجية التي تلي التعليمة switch. بما ان وجود التعليمة break اختياري، ففي حالة عدم وجودها سيقوم البرنامج بتنفيذ التعليمة التالية في switch.

+ +

مثال

+ +

في المثال التالي، اذا كان fruittype يساوي "Bananas"،  سيقوم البرنامج بتنفيذ  التعليمات البرمجية المرتبطة بالحالة 'case: 'Banana. عندما سسيجد break، سيقوم بايقاف switch وينفذ التعليمات البرمجية التي تليها. اذا لم يجد break سينفذ التعليمة البرمجية المرتبطة بالحالة 'case: 'Cherries ايضا. 

+ +
switch (fruittype) {
+  case 'Oranges':
+    console.log('Oranges are $0.59 a pound.');
+    break;
+  case 'Apples':
+    console.log('Apples are $0.32 a pound.');
+    break;
+  case 'Bananas':
+    console.log('Bananas are $0.48 a pound.');
+    break;
+  case 'Cherries':
+    console.log('Cherries are $3.00 a pound.');
+    break;
+  case 'Mangoes':
+    console.log('Mangoes are $0.56 a pound.');
+    break;
+  case 'Papayas':
+    console.log('Mangoes and papayas are $2.79 a pound.');
+    break;
+  default:
+   console.log('Sorry, we are out of ' + fruittype + '.');
+}
+console.log("Is there anything else you'd like?");
+ +
+

ملاحظة : لمزيد من التفاصيل حول التعليمة  switch.

+
+ +

التعليمات المعالجة للاستثناءات

+ +
+

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

+ +

بصفة عامة، الاستثناءات هي عبارة عن آلية برمجية لمعالجة أخطاء التنفيذ المحتمل وقوعها.

+ +

 

+
+ +

يمكنك قذف (توليد)  الاستثناءات من خلال التعليمة throw والتعامل معها باستخدام التعليمة try...catch

+ + + +

انواع الاستثناءات

+ +

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

+ + + +

التعليمة throw

+ +

التعليمة throw تقذف الاخطاء. عند حدوث خطأ، عادة سوف تتوقف جافا سكريبت، وستولد رسالة للاعلان عن الخطأ. المصطلح التقني لهذه العملية هو : الجافاسكريبت ستقذف (throw) الخطأ. التعليمة throw تمكتك من انشاء خطأ حسب رغبتك. المصطلح التقني لهذه العملية هو: اقذف استثناءا (throw an exception).

+ +

إستخدِم التعليمة throw لقذف الإستثناء، عنما تريد قذف إستثناءا، عليك تحديد التعبير (expression) الذي سيحتوي على القيمة التي ستقذف:

+ +
throw expression;
+
+ +

يمكنك قذف اي استثناء، وليس مجرد تعبيرات من نوع معين. التعليمة البرمجية التالية تقذف استثناءات لمختلف انواع البيانات:

+ +
throw 'Error2';   // String type
+throw 42;         // Number type
+throw true;       // Boolean type
+throw {toString: function() { return "I'm an object!"; } };
+
+ +
ملحوظة : يمكنك تحديد كائن عندما ستقوم بقذف الاستثناء. يمكنك بعد ذالك الاشارة إلى خصائص الكائن في البلوك catch. يقوم المثال التالي بإنشاء الكائن myUserException من النوع UserException واستحدامه في التعليمة throw.
+ +
// Create an object type UserException
+function UserException(message) {
+  this.message = message;
+  this.name = 'UserException';
+}
+
+// Make the exception convert to a pretty string when used as a string
+// (e.g. by the error console)
+UserException.prototype.toString = function() {
+  return this.name + ': "' + this.message + '"';
+}
+
+// Create an instance of the object type and throw it
+throw new UserException('Value too high');
+ +
+

لمزيد من المعلومات حول هذه التعليمة، راجع صفحة مرجع الجافا سكريبت  throw.

+
+ +

التعليمة try...catch

+ +

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

+ +

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

+ +


+ المثال التالى يستخدم التعليمة try...catch. ويقوم باستدعاء دالة تعود باسم الشهر من مصفوفة بناء على القيمة التي تم تمريرها إلى الدالة. إذا كانت القيمة لا تتوافق مع رقم الشهر (1-12)، سيولّد استثناء مع القيمة "InvalidMonthNo" فيما تقوم التعليمة البرمجية في البلوك catch بتعين القيمة unknown إلى المتغير monthName.

+ +
function getMonthName(mo) {
+  mo = mo - 1; // Adjust month number for array index (1 = Jan, 12 = Dec)
+  var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul',
+                'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
+  if (months[mo]) {
+    return months[mo];
+  } else {
+    throw 'InvalidMonthNo'; //throw keyword is used here
+  }
+}
+
+try { // statements to try
+  monthName = getMonthName(myMonth); // function could throw exception
+}
+catch (e) {
+  monthName = 'unknown';
+  logMyErrors(e); // pass exception object to error handler -> your own function
+}
+
+ +

The catch block

+ +

يمكنك استخدام البلوك  catch للامساك بجميع الاستثناءات التي سيتم قذفها من البلوك try.

+ +
catch (catchID) {
+  statements
+}
+
+ +

البلوك catch يحدد الايدي catchID الذي سيمسك القيمة المحددة من طرف التعليمة throw، يمكنك استخدام هذا الايدي للحصول على معلومات حول الاستثناء الذي سيقذف. جافا سكريبت ستنشئ هذا الايدي عند دخوله الى البلوك catch. يبدا عمر هذا الايدي من لحظة دخوله الى البلوك catch، وينتهي عندما ينتهي البلوك catch من التنفيذ.

+ +

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

+ +
try {
+  throw 'myException'; // generates an exception
+}
+catch (e) {
+  // statements to handle any exceptions
+  logMyErrors(e); // pass exception object to error handler
+}
+
+ +

The finally block

+ +

البلوك finally سيحتوي على التعليمات البرمجية التي سيقوم بتنفيذها بعدما تنفذ البلوكات try و catch، وايضا سينفذ قبل تنفيذ التعليمات البرمجية التي تلي التعليمة try...catch. سينفذ البلوك finally سواء تم قذف الاستثناء ام لا، اذا تم قذف الاستثناء، ستنفذ التعليمات البرمجية في البلوك finally حتى وان لم يتم معالجة الاستثناء في البلوك catch.

+ +

يمكنك استخدام البلوك finally لجعل السكريبت الخاص بك يفشل بأمان عند حدوث استثناء، على سبيل المثال، اذا كنت في حاجة إلى تحرير مورد، او لغلق ال flux، الخ. المثال التالي يفتح ملف ثم ينفذ التعليمات البرمجية لهذا ملف (server-side JavaScript يسمح لك بالوصول الى الملفات). اذا تم قذف استثناء في حين أن الملف مفتوح، البلوك finally ستغلق هذا الملف قبل فشل السكريبت.

+ +
openMyFile();
+try {
+  writeMyFile(theData); //This may throw a error
+} catch(e) {
+  handleError(e); // If we got a error we handle it
+} finally {
+  closeMyFile(); // always close the resource
+}
+
+ +

عندما سيقوم البلوك finally بارجاع قيمة، تصبح هذه القيمة قيمة الإرجاع من كامل المجموعة  try-catch-finally بغض النظر عن التعليمات البرمجية العائدة من البلوكات  try و catch.

+ +
function f() {
+  try {
+    console.log(0);
+    throw 'bogus';
+  } catch(e) {
+    console.log(1);
+    return true; // this return statement is suspended
+                 // until finally block has completed
+    console.log(2); // not reachable
+  } finally {
+    console.log(3);
+    return false; // overwrites the previous "return"
+    console.log(4); // not reachable
+  }
+  // "return false" is executed now
+  console.log(5); // not reachable
+}
+f(); // console 0, 1, 3; returns false
+
+ +

الكتابة فوق القيم العائدة من قبل البلوك finally ينطبق أيضا على قذف الاستثناءات او اعادة القذف داخل البلوك catch:

+ +
function f() {
+  try {
+    throw 'bogus';
+  } catch(e) {
+    console.log('caught inner "bogus"');
+    throw e; // this throw statement is suspended until
+             // finally block has completed
+  } finally {
+    return false; // overwrites the previous "throw"
+  }
+  // "return false" is executed now
+}
+
+try {
+  f();
+} catch(e) {
+  // this is never reached because the throw inside
+  // the catch is overwritten
+  // by the return in finally
+  console.log('caught outer "bogus"');
+}
+
+// OUTPUT
+// caught inner "bogus"
+ +

التعليمات try...catch المتداخلة

+ +

يمكن عمل واحدة او اكثر من التعليمات try...catch المتداخلة.  شرط عدم توفر try...catch الداخلية على البلوك catch، تتطلب وجود البلوك finally والتعليمة try...catch الخارجية سوف تستخدم البلوك catch ليتم التحقق من المطابقة. راجع nested try-blocks في صفحة المرجع الخاص بالتعليمة try...catch.

+ +

باستخدام الكائنات Error

+ +

اعتماداً على نوع الخطأ، من الممكن استخدام الخصائص name و message للحصول على رسالة أكثر دقة. عموما لدينا الخاصية name التي ستعرض نوع الخطا الذي حدث (مثلا: DOMException او Error). والخاصية message التي ستعرض رسالة الخطأ لوصف هذا الخطا (تستخدم عادة عندما نريد تحويل او عرض نص الخطأ). على سبيل المثال:

+ +
try {
+  throw new Error('Whoops!');
+} catch (e) {
+	if( e.message === 'Whoops!'){
+		e.message = "Costume message";
+	}
+  console.log(e.name + ': ' + e.message); // Error: Costume message
+}
+ +

اذا كنت ترغب في انشاء اخطاء خاصة بك، يمكتك استخدام المنشئ Error من أجل الاستفادة من خصائصه. على سبيل المثال:

+ +
function doSomethingErrorProne() {
+  if (ourCodeMakesAMistake()) {
+    throw (new Error('The message'));
+  } else {
+    doSomethingToGetAJavascriptError();
+  }
+}
+....
+try {
+  doSomethingErrorProne();
+} catch (e) {
+  console.log(e.name); // logs 'Error'
+  console.log(e.message); // logs 'The message' or a JavaScript error message)
+}
+ +

Promises

+ +

ابتداءا من ECMAScript2015. اصبح لجافاسكريبت الكائن Promise والذي يسمح لك بالتحكم في التدفق والعمليات المتزامنة.

+ +

Promise هو احد هذه الحالات:

+ + + +

+ +

تحميل صورة ب XHR

+ +

مثال بسيط باستخدام Promise و XMLHttpRequest في مستودع الاكواد MDN GitHub. راجع المثال js-examples. يمكنك ايضا مراجعة see it in action. تم التعليق على كل خطوة لتمكينك من متابعة سير عملية Promise و XHR. هذا الإصدار من دون تعليقات، يعرض تدفق ال Promise:

+ +
function imgLoad(url) {
+  return new Promise(function(resolve, reject) {
+    var request = new XMLHttpRequest();
+    request.open('GET', url);
+    request.responseType = 'blob';
+    request.onload = function() {
+      if (request.status === 200) {
+        resolve(request.response);
+      } else {
+        reject(Error('Image didn\'t load successfully; error code:'
+                     + request.statusText));
+      }
+    };
+    request.onerror = function() {
+      reject(Error('There was a network error.'));
+    };
+    request.send();
+  });
+}
+ +

للحصول على معلومات أكثر تفصيلاً، راجع {{jsxref("Promise")}} في صفحة المرجع.

+ +
+
{{PreviousNext("Web/JavaScript/Guide/Grammar_and_types", "Web/JavaScript/Guide/Loops_and_iteration")}}
+
+
diff --git a/files/ar/web/javascript/guide/grammar_and_types/index.html b/files/ar/web/javascript/guide/grammar_and_types/index.html new file mode 100644 index 0000000000..be90ff189a --- /dev/null +++ b/files/ar/web/javascript/guide/grammar_and_types/index.html @@ -0,0 +1,680 @@ +--- +title: قواعد اللغة وأنواع البيانات +slug: Web/JavaScript/Guide/Grammar_and_types +translation_of: Web/JavaScript/Guide/Grammar_and_types +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Introduction", "Web/JavaScript/Guide/Control_flow_and_error_handling")}}
+ +

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

+ +

الأساسيات

+ +
+

معظم التعبيرات الخاصة بجافا سكريبت مشتقة من Java، ولكنها تاثرت أيضا ب Awk، بيرل وبايثون.

+ +

الجافاسكريبت حساسة لحالة الاحرف myName ليس نفسه myname، الجافاسكريبت تستخدم مجموعة من رموز ال Unicode.

+ +

في الجافاسكريبت، التعليمات البرمجية تسمى {{Glossary("Statement", "statements")}}  وتكون مفصولة بفاصلة منقوطة (؛).  الفراغات، وعلامات التبويب (tabs) والأسطر الجديدة تسمى مساحة خالية.  يتم تحليل نص شيفرة المصدر لجافا سكريبت من اليسار إلى اليمين ويتم تحويلها إلى سلسلة من العناصر والمدخلات، وهي الرموز المميزة (tokens)، رموز التحكم (control characters)، ونهايات الاسطر (line terminators)، والتعليقات والمسافات الخالية، ECMAScript تحدد ايضا الكلمات المحجوزة مثل (if او var او return الخ)  والبيانات الحرفية، كما لها قواعد للإدراج التلقائي للفاصلة المنقوطة (ASI) لانهاء التعليمة البرمجية. ومع ذالك، من المستحسن دائماً إضافة الفاصلة المنقوطة (;) نهاية التعليمة البرمجية الخاصة بك لتجنب الاثار الجانبية، للحصول على مزيد من المعلومات، راجع قاموس جافا سكريبت.

+ +

التعليقات

+ +

صيغة التعليقات هي نفسها كما هو الحال في ++C و في العديد من اللغات الأخرى:

+ +
// a one line comment
+
+/* this is a longer,
+   multi-line comment
+ */
+
+/* You can't, however, /* nest comments */ SyntaxError */
+ +

الاعلانات

+ +

هناك ثلاثة أنواع من الإعلانات في جافا سكريبت.

+ +
+
{{jsxref("Statements/var", "var")}}
+
الاعلان عن متغير (اي، الكلمة المحجوزة var متبوعة باسم المتغير var x)، تهيئته (اي، اسناد قيمة اولية له var x = value ) / اختياري.
+
{{jsxref("Statements/let", "let")}}
+
الاعلان عن متغير محلي ضمن نطاق الكتلة (ال block هو مجموعة من التعليمات البرمجية بين اقواس متعرجة {})، تهيئته / اختياري.
+
{{jsxref("Statements/const", "const")}}
+
الاعلان عن ثابت قابل للقراءة فقط.
+
+ +

المتغيرات

+ +

يمكنك استخدام المتغيرات كأسماء رمزية للقيم في التطبيق الخاص بك. أسماء المتغيرات، تسمى {{Glossary("Identifier", "identifiers")}}, وتخضع لقواعد معينة.

+ +

المتغير في جافاسكريبت، يجب أن يبدأ بحرف، أو رمز (_)، أو علامة الدولار ($). يمكن أيضا أن تكون الأحرف اللاحقة أرقاما (0-9). ولأن الجافاسكريبت حساسة لحالة الأحرف، فإن الحروف تشمل الأحرف من "A" الى "Z" (أحرف كبيرة) او أحرف من  "a" الى "z" (أحرف صغيرة).

+ +

يمكنك استخدام معظم أحرف ال ISO 8859-1 أو Unicode مثل å و ü في المتغيرات. لمزيد من المعلومات راجع مذه المدونة كما يمكنك أيضا استخدام  Unicode escape sequences كرموز مع المتغيرات.

+ +

بعض الامثلة عن اسماء المتغيرات الجائزة :  Number_hits, temp99, $credit, and_name.

+ +

الاعلان عن المتغيرات

+ +

يمكنك تعريف متغير بثلاث طرق:

+ + + +

اختبار المتغيرات

+ +

الاعلان عن متغير باستخدام var او let من دون تهيئته، سيتم تهيئته بالقيمة {{jsxref("undefined")}} (بشكل تلقائي من قبل الجافاسكريبت).

+ +
+

ملاحظة: جافا سكريبت في الوضع الصارم ("use strict") لا تسمح باستخدام المتغيرات إذا لم يتم الإعلان عنها

+
+ +

محاولة الوصول إلى متغير غير معلن عنه سيؤدي الى ال {{jsxref("ReferenceError")}}. وايضا محاولة الوصول الى متغير لم يتم تهيئته بعد سيعود ب undefined :

+ +
var a;
+console.log("The value of a is " + a); // logs "The value of a is undefined"
+console.log("The value of b is " + b); // throws ReferenceError exception
+
+ +

يمكنك استخدام undefined لاختبار ما إذا كان المتغير مهيأ ام لا. في التعليمة البرمجية التالية، المتغير input غير مهيأ، ستقوم التعليمة if باختبار ما اذا كان فعلا المتغير input غير مهيأ، بمعنى اخر (هل صحيح/true ان المتغير input غير مهيأ).

+ +
var input;
+if(input === undefined){
+  doThis();
+} else {
+  doThat();
+}
+
+ +

القيمة undefined تتصرف ك false عندما تستخدم في السياق المنطقي. على سبيل المثال، التعليمة البرمجية التالية ستقوم بتنفيذ الدالة myFunction بسبب ان العنصر الاول في المصفوفة myArray غير مهيأ:

+ +
var myArray = [];
+if (!myArray[0]) myFunction();
+ +
+

تذكير:  تذكر ان "المتغير الغير مهيأ يتم تهيئته بشكل تلقائي بالقيمة undefined" كما ذكرنا اعلاه.

+
+ +

القيمة undefined تتحول الى NaN (ليسا رقما) عندما تستخدم في السياق الرقمي.

+ +
var a;
+a + 2 = NaN
+ +

عند اختبار متغير يحمل القيمة {{jsxref("null")}} ستتصرف القيمة null ك 0 في السياق الرقمي وك false في السياق المنطقي على سبيل المثال:

+ +
var n = null;
+console.log(n * 32); // Will log 0 to the console
+
+ +

نطاق المتغيرات - Variable scope

+ +

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

+ +

في جافاسكريبت قبل ECMAScript 2015، لم يكن للتعليمة البرمجية block statement نطاق (scope) خاص بها، المتغير الذي يتم تعريفه داخل block هو اما متغير محلى للدالة او متغير محلي للنطاق العام حسب تواجد هذا البلوك.

+ +

يبين المثال التالى كيف ان ال block ليس له نطاق خاص به، مخرجات التعليمة البرمجية التالية ستكون 5، بسبب ان المتغير x تم تعريفه في النطاق العام وليس في نطاق ال block، وفي هذه الحالة ال block هي التعليمة if.

+ +
if (true) {
+  var x = 5;
+}
+console.log(x);  // 5
+
+ +

يتغير هذا السلوك، عند الاعلان عن متغير باستخدام let المعتمدة في ECMAScript 6، الان اصبح لل block نطاقا خاصا به: 

+ +
if (true) {
+  let y = 5;
+}
+console.log(y);  // ReferenceError: y is not defined
+
+ +

رفع المتغيرات - Variable hoisting

+ +

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

+ +

لو تاملت قليلا في التعليمة البرمجة التالية، ستتسائل ما الذي جعل المتغير x يعود ب undefined وليس ب ReferenceError. السبب هو ان الجافاسكريبت ترفع الاعلان (var x) فقط، ولا ترفع التهيئة (3=). وبالتالي وبسبب الرفع الذي حدث "في الخفاء"، x اعلن عنه قبل استخدامه، لكن بسبب ان التهيئة لم ترفع، فقيمة x ستعود ب undefined. ونفس الشئ حصل مع المتغير myvar، بحيث تم رفعه الى اعلى نطاق الدالة. فيما تم رفع المتغير x الى اعلى النطاق العام.

+ +
/*---Example 1---*/
+
+console.log(x === undefined); // logs "true"
+var x = 3;
+
+
+/*---Example 2---*/
+
+// will return a value of undefined
+var myvar = "my value";
+
+(function() {
+  console.log(myvar); // undefined
+  var myvar = "local value";
+})();
+
+ +

الامثلة اعلاه، ستفسر بالشكل التالي:

+ +
/*---Example 1---*/
+
+var x;
+console.log(x === undefined); // logs "true"
+x = 3;
+
+
+/*---Example 2---*/
+
+var myvar = "my value";
+
+(function() {
+  var myvar;
+  console.log(myvar); // undefined
+  myvar = "local value";
+})();
+
+ +

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

+ +

في ECMAScript 2015، المتغير let سوف لن يتم رفعه الى اعلى نطاق ال block. واستخدام متغير داخل block قبل الاعلان عنه سينتج عنه ReferenceError. لان المتغير يعتبر في "منطقة زمنية ميتة" من بداية ال block حتى يتم معالجته بالإعلان.

+ +
console.log(x); // ReferenceError
+let x = 3;
+ +

رفع  الدوال - Function hoisting

+ +

بالنسبة للدوال، فقط ال function declaration هي التي سترفع الى الاعلى وليست ال function expression.

+ +
/* Function declaration */
+
+foo(); // "bar"
+
+function foo() {
+  console.log('bar');
+}
+
+
+/* Function expression */
+
+baz(); // TypeError: baz is not a function
+
+var baz = function() {
+  console.log('bar2');
+};
+
+ +

المتغيرات العامة

+ +

المتغيرات العامة، في حقيقة الامر هي خصائص للكائن العام. في صفحات الويب الكائن العام هو window. لذا يمكنك انشاء او الوصول إلى المتغيرات العامة باستخدام الصيغة window.variable.

+ +

كما يمكنك ايضا الوصول إلى المتغيرات العامة المعلن عنها في نافذة أو frame من نافذة اخرى او frame عن طريق تحديد النافذة او اسم ال frame. على سبيل المثال، اذا كان لدينا متغير معلن عنه في الوثيقة، واسمه phoneNumber,  يمكنك الوصول الى هذا المتغير من ال iframe باستخدام الصيغة parent.phoneNumber

+ +

الثوابت - Constants

+ +

يمكنك إنشاء ثابت للقراءة فقط، والمسمى بالكلمة المحجوزة {{jsxref("Statements/const", "const")}} طريقة التعبير عن الثابت هي نفسها طريقة التعبير عن المتغير: يجب ان يبدا بحرف او underscore او ($)dollar sign  ويمكن يحتوي على alphabetic، ارقام، او underscore او رموز. 

+ +
const prefix = '212';
+
+ +

الثابت، لا يمكن تغيير قيمته من خلال الاحالة او باعادة الاعلان عنه اثناء تشغيل السكريبت. ولا بد من تهيئته.

+ +

قواعد نطاق الثابت هي نفسها قواعد المتغير let فيما يخص نطاق ال block. اذا لم يتم تعيين الكلمة المحجوزة const سيتم معاملته معاملة المتغير.

+ +

اسم الثابت لا يجب ان يكون هو نفسه اسم دالة او متغير في نفس النطاق. على سبيل المثال:

+ +
// THIS WILL CAUSE AN ERROR
+function f() {};
+const f = 5;
+
+// THIS WILL CAUSE AN ERROR ALSO
+function f() {
+  const g = 5;
+  var g;
+
+  //statements
+}
+
+ +

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

+ +
const MY_OBJECT = {'key': 'value'};
+MY_OBJECT.key = 'otherValue';
+ +

هياكل البيانات والأنواع - Data structures and types

+ +

أنواع البيانات

+ +

المعيار الاحدث ل ECMAScript يحدد سبعة من انواع البيانات:

+ + + +

على الرغم من أن هذه الكمية من أنواع البيانات صغيرة نسبيا، الا أنها تتيح لك القيام بمهام مفيدة مع التطبيقات الخاصة بك. الكائنات {{jsxref("Object", "Objects")}} والدوال {{jsxref("Function", "functions")}} هي العناصر الأساسية الأخرى في اللغة، يمكنك اعتبار الكائنات كحاويات لمجموعة من المتغرات المرتبطة بالكائن، والدوال هي الوظائف التي سيقوم التطبيق الخاص بك بتنفيذها.

+ +

تحويل نوع البيانات - Data type conversion

+ +

الجافاسكريبت لغة حيوية، وهذا يعني انك لست بحاجة لتحديد نوع البيانات للمتغير اثناء تعريفه، على غرار لغات برمجة اخرى (جافا مثلا)، لانه سيتم تحويل أنواع البيانات تلقائياً حسب الحاجة أثناء تنفيذ السكريبت. على سبيل المثال، يمكنك تعريف متغير كالتالي:

+ +
var answer = 42;
+
+ +

وفي وقت لاحق، يمكنك تغيير نوع البيانات، من النوع Number الى النوع String، عن طريق تعيين سلسلة حرفية لنفس المتغير، على سبيل المثال:

+ +
answer = "Thanks for all the fish...";
+
+ +

بفضل حيوية الجافا سكريبت، فهذه التعليمة البرمجية لن تتسبب في اية رسالة خطأ.

+ +

اثناء الجمع بين القيم الرقمية والسلاسل الحرفية باستخدام عامل التشغيل (+)، فجافاسكريب تحول القيم الرقمية الى سلاسل حرفية. على سبيل المثال، انظر في التعليمات البرمجية التالية:

+ +
x = "The answer is " + 42 // "The answer is 42"
+y = 42 + " is the answer" // "42 is the answer"
+
+ +

في التعبيرات التي تحتوي على عوامل أخرى، جافا سكريبت لا تقوم بتحويل القيم الرقمية إلى سلاسل حرفية. على سبيل المثال:

+ +
"37" - 7 // 30
+"37" + 7 // "377"
+
+ +

تحويل القيم النصية إلى أرقام

+ +

في حالة أن لدينا قيمة تمثل عدد في الذاكرة وهي على شكل سلسلة حرفية ("10")، ونريد تحويلها الى قيمة رقمية، سنحتاج الى وظائف جاهزة في الجافاسكريبت تقوم بعملية التحويل.

+ + + +

المثال التالي يبين كيفية استخدام الوظيفة parseInt ببارامتر واحد، لمزيد من المعلومات حول البرامتر الثاني واشياء اخرى، راجع {{jsxref("parseInt", "()parseInt")}}:

+ +
var str = "10";
+console.log( typeof str ) // string
+var parse = parseInt(str)
+console.log( typeof parse ) // number.
+ +

المثال التالي يبين كيفية استخدام الوظيفة parseFloat، لمزيد من المعلومات، راجع {{jsxref("parseFloat", "()parseFloat")}}

+ +
var str = "3.14";
+console.log( typeof str ) // string
+var parse = parseInt(str)
+console.log( typeof parse ) // number.
+ +

طريقة بديلة لتحويل قيمة رقمية على شكل سلسلة حرفية، باستخدام العامل (unary plus)+

+ +
"1.1" + "1.1" = "1.11.1"
+(+"1.1") + (+"1.1") = 2.2
+// Note: the parentheses are added for clarity, not required.
+ +

البيانات الحرفية - Literals

+ +

المقصود بالبيانات الحرفية، هو استخددام الكائن بالصيغة الاسهل، مثلا، بدلا من استخدام الكائن new Array(elm1,elm2...) نستخدم [...elm1,elm2] وهكذا مع جميع الكائنات الاخرى.

+ +

يمكنك استخدام البيانات الحرفية لتمثيل القيم في جافا سكريبت. وهي قيم ثابتة، ليست متغيرات، والتي ترد حرفيا في السكريبت. يصف هذا القسم الأنواع التالية من البيانات الحرفية :

+ + + +

بيانات المصفوفة الحرفية - Array literals

+ +

بيانات المصفوفة الحرفية، هي قائمة تتكون من صفر او اكثر من التعبيرات، كل تعبير فيها يمثل عنصر المصفوفة، محاطة بأقواس مربعة ([]). عندما تقوم بإنشاء مصفوفة باستخدام البيانات الحرفية ، ستقوم بتهيئتها بقيم محددة لتكوين عناصرها، طول المصفوفة هو عدد البارامترات/العناصر المحددة لها.

+ +

ينشئ المثال التالي مصفوفة القهوة مع ثلاثة عناصر وطولها ثلاثة:

+ +
var coffees = ["French Roast", "Colombian", "Kona"];
+
+ +
+

ملاحظة: بيانات المصفوفة الحرفية هي نوع من مهيئ الكائن.  Using Object Initializers.

+
+ +

إذا تم إنشاء مصفوفة باستخدام البيانات الحرفية في سكريبت على أعلى مستوى (top-level script)، فجافاسكريبت ستفسر هذه المصفوفة في كل مرة يتم اختبار التعبير الذي يحتوي على المصفوفة. بالإضافة الى ذالك، البيانات الحرفية المستخدمة في دالة يتم إنشاءها كل مرة يتم فيها استدعاء الدالة. 

+ +

 البيانات الحرفية هي كذالك Array objects راجع {{jsxref("Array")}} و Indexed collections لمعرفة تفاصيل ال Array objects.

+ +

فواصل إضافية في ال array literals

+ +

لست بحاجة لتحديد جميع العناصر في بيانات المصفوفة الحرفية. اذا قمت بوضع فاصلتات متتاليتان سيم انشاء المصفوفة مع undefined مكان العنصر الغير محدد.

+ +
var fish = ["Lion", , "Angel"];
+
+ +

تحتوي هذه المصفوفة على عنصرين بقيم، وعنصر واحد فارغ (fish[0] هو "Lion"، و fish[1] هو undefined، و fish[2] هو "Angel").

+ +

إذا قمت بتضمين فاصلة زائدة في نهاية قائمة العناصر، سيتم تجاهل تلك الفاصلة. في المثال التالي، طول المصفوفة هو ثلاثة. وليس هناك myList[3]. جميع الفواصل الأخرى في القائمة تشير الى عنصر جديد.

+ +
var myList = ['home', , 'school', ];
+
+ +

في المثال التالي، طول المصفوفة هو أربعة، و myList[0] و myList[2] في عداد المفقودين.

+ +
var myList = [ , 'home', , 'school'];
+
+ +

في المثال التالي، طول المصفوفة أربعة، myList[1] و myList[3] في عداد المفقودين. وسيتم تجاهل الفاصلة الأخيرة فقط.

+ +
var myList = ['home', , 'school', , ];
+
+ +

فهم سلوك الفواصل الاضافية مهم لفهم جافا سكريبت كلغة، ولكن عند كتابة التعليمات البرمجية الخاصة بك: من الافضل الإعلان الصريح عن العناصر المفقودة ب undefined، مثل هذه الممارسات ستزيد من وضوح التعليمات البرمجية الخاصة بك ويصبح من السهل صيانتها.

+ +
+

ملاحظة: يمكن للفواصل الزائدة ان تخلق أخطاءا في الاصدارات القديمة من المتصفحات. من الافضل إزالتها.

+
+ +

Boolean literals

+ +

النوع Boolean يتكون من بيانين حرفيين وهما :  true و false.

+ +

لا ينبغي الخلط بين القيم المنطقية الاولية true و false مع القيم true و false لل Boolean object. الكائن Boolean هو من يحتضن انوع البيانات المنطقية الاولية. راجع {{jsxref("Boolean")}} لمزيد من المعلومات.

+ +

الأعداد الصحيحة - Integers

+ +

يمكن التعبير عن الأعداد الصحيحة بالنسبة لكل من العدد الصحيح العشري ب (base 10)، ونظام العد السداسي عشر ب (base 16) والرقم الثماني ب (base 8) والثنائي ب (base 2)  .

+ + + +

بعض الأمثلة عن البيانات الحرفية لعدد صحيح :

+ +
0, 117 and -345 (decimal, base 10)
+015, 0001 and -077 (octal, base 8)
+0x1123, 0x00111 and -0xF1A7 (hexadecimal, "hex" or base 16)
+
+ +

لمزيد من المعلومات، راجع Numeric literals in the Lexical grammar reference.

+ +

بيانات العدد الكسري الحرفي

+ +

البيانات الحرفية لعدد كسري  يمكن أن تتكون من الأجزاء التالية:

+ + + +

الأس هو "e" أو "E" متبوعاً بعدد صحيح، والذي يمكن توقيعه (يسبقه "+" أو "-"). يجب أن يكون قيمة حرفية floating-point ويجب ان يحتوي على رقم واحد على الأقل والنقطة العشرية أو "e"  (أو "E").

+ +
[(+|-)][digits][.digits][(E|e)[(+|-)]digits]
+
+ +

على سبيل المثال:

+ +
3.14
+2345.789
+.3333333333333333333
+-.283185307179586
+
+ +

بيانات الكائن الحرفي - Object literals

+ +

بيانات الكائن الحرفية هي عبارة عن قائمة تتكون من صفر او اكثر من الازواج، كل زوجين  عبارة عن اسم خاصية الكائن وقيمتها، محاطة بأقواس متعرجة ({}). لا يجب استخدام البيانات الحرفية للكائن في بداية التعليمة البرمجية خاصتك. لان هذا سيؤدي إلى خطأ او سيقوم بسلوك عكس المتوقع منه، بسبب ان الجافاسكريبت ستفسر } على انه بداية ل block.

+ +

في المثال التالي. العنصر الاول للكائن car يمثل الخاصية  myCar، تحمل القيمة النصية "Saturn"، العنصر الثاني هي الخاصية getCar، قيمتها هو ناتج الدالة carTypes("Honda")، العنصر الثالث، هي الخاصية special، قيمتها متغير خارجي وهو  sales.

+ +
var Sales = "Toyota";
+
+function CarTypes(name) {
+  if (name == "Honda") {
+    return name;
+  } else {
+    return "Sorry, we don't sell " + name + ".";
+  }
+}
+
+var car = { myCar: "Saturn", getCar: CarTypes("Honda"), special: Sales };
+
+console.log(car.myCar);   // Saturn
+console.log(car.getCar);  // Honda
+console.log(car.special); // Toyota
+
+ +

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

+ +
var car = { manyCars: {a: "Saab", "b": "Jeep"}, 7: "Mazda" };
+
+console.log(car.manyCars.b); // Jeep
+console.log(car[7]); // Mazda
+
+ +

أسماء خصائص الكائن يمكن أن تكون أي سلسلة حرفية، بما في ذالك السلسلة الحرفية الفارغة, اذا كان اسم الخاصية عبارة عن احد المعرفات identifier، الغير مسموح بها (ما لا يمكن استخدامه كاسم للمتغر مثلا) او ان يكون اسم الخاصية عبارة عن رقم، فيجب إحاطتها بعلامات الاقتباس. اسماء الخاصية الغير مسموح بها كمعرفات لا يمكن الوصول اليها بطريقة نقطة التدوين (.)، وانما تستخدم طريقة الاقواس المربعة ("[]") للوصول اليها او التعديل عليها.

+ +
var unusualPropertyNames = {
+  "": "An empty string",
+  "!": "Bang!"
+}
+console.log(unusualPropertyNames."");   // SyntaxError: Unexpected string
+console.log(unusualPropertyNames[""]);  // An empty string
+console.log(unusualPropertyNames.!);    // SyntaxError: Unexpected token !
+console.log(unusualPropertyNames["!"]); // Bang!
+ +

ابتداءا من ES2015، اصبح من الممكن : تعيين ال prototype  أثناء إنشاء الكائن. استخدام التعيين المختصر ك  foo: foo، تعيين الوظائف، استدعاء وظائف الكائن الاب بواسطة super، استخدام أسماء الخصائص المحوسبة مع التعبيرات.

+ +
var obj = {
+    // __proto__
+    __proto__: theProtoObj,
+    // Shorthand for ‘handler: handler’
+    handler,
+    // Methods
+    toString() {
+     // Super calls
+     return 'd ' + super.toString();
+    },
+    // Computed (dynamic) property names
+    [ 'prop_' + (() => 42)() ]: 42
+};
+ +

يبين المثال التالي الطرق الصحيحة لكيفية الوصول الى الكائن:

+ +
var foo = {a: "alpha", 2: "two"};
+console.log(foo.a);    // alpha
+console.log(foo[2]);   // two
+//console.log(foo.2);  // Error: missing ) after argument list
+//console.log(foo[a]); // Error: a is not defined
+console.log(foo["a"]); // alpha
+console.log(foo["2"]); // two
+
+ +

بيانات التعبير القياسي الحرفي - RegExp literals

+ +

Regex هو نمط (pattern) محصور بين خطوط مائلة. يبين المثال التالي كيفبة التعبير عن بيانات التعبيرات القياسية الحرفية.

+ +
var re = /ab+c/;
+ +

بيانات السلاسل النصية الحرفية - String literals

+ +

السلسلة النصية، هي عبارة عن صفر أو أكثر من الأحرف محاطة بعلامات اقتباس اما منفردة (') أو مزدوجة ("). يبين المثال التالي كيفية استخدام كل من الاقتباسات المنفردة والمزدوجة:

+ +
'foo'
+"bar"
+'1234'
+'one line \n another line'
+"John's cat"
+
+ +

من الممكن استدعاء وظائف الكائن String على السلاسل الحرفية. تقوم الجافاسكريبت بتحويل السلاسل الحرفية الى الكائن String بشكل مؤقت، بعدما تستدعى الوظائف، يتم استبعاد/تدمير الكائن String المؤقت، يمكنك ايضا استخدام  الخاصية String.length مع القيم النصية:

+ +
console.log("John's cat".length)
+// Will print the number of symbols in the string including whitespace.
+// In this case, 10.
+
+ +

ابتداءا من ES2015، يمكنك استخدام البيانات الحرفية كقوالب  (template literals)، هذه القوالب النصية هي نفسها المستخدمة في  Perl ،Python، الخ. يمكنك استخدامها لانشاء سلسلة حرفية واحدة على عدة اسطر دون الحاجة لاستخدام اسلوب التهريب (اضافة "\" في نهاية كل سطر). يمكن من خلالها ايضا إنشاء سلاسل حرفية جديدة اعتمادا على مجموعة متقطعة من السلاسل الحرفية المحددة سلفا وذالك من خلال هذه الصيغة الجديدة { result }$، القيمة الممرة result هي القيمة التي ستظهر مع السلسلة الحرفية الجديدة،  وهي عبارة عن مخرجات لاي تعليمة برمجية اخرى مثل (function, literal object, var...).  وايضا يمكنك من خلالها تجنب هجمات الحقن (injection attacks). 

+ +
// Basic literal string creation
+`In JavaScript '\n' is a line-feed.`
+
+// Multiline strings
+`In JavaScript template strings can run
+ over multiple lines, but double and single
+ quoted strings cannot.`
+
+// String interpolation
+var name = 'Bob', time = 'today';
+`Hello ${name}, how are you ${time}?`
+
+// Construct an HTTP request prefix is used to interpret the replacements and construction
+POST`http://foo.org/bar?a=${a}&b=${b}
+     Content-Type: application/json
+     X-Credentials: ${credentials}
+     { "foo": ${foo},
+       "bar": ${bar}}`(myOnReadyStateChangeHandler);
+ +

من الأفضل استخدام السلاسل الحرفية قدر الامكان، الا اذا كنت في حاجة ماسة لاستخدام الكائن String، وقتها يمكنك استخدامه ايضا. راجع الكائن {{jsxref("String")}} للاطلاع على كافة التفاصيل.

+ +

استخدام الرموز الخاصة مع السلاسل النصية

+ +

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

+ +
"one line \n another line"
+
+ +

يبين الجدول التالي، الرموز الخاصة التي يمكنك استخدامها مع السلاسل الحرفية لجافاسكريبت.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
جدول الرموز الخاصة لجافاسكريبت
CharacterMeaning
0\Null Byte  - بايت فارغ
b\Backspace  - مسافة للخلف
f\Form feed  -  نموذج تغذية
n\New line  -  سطر جديد
r\Carriage return  -  حرف الإرجاع
t\Tab  -  علامة التبويب
v\Vertical tab - علامة التبويب العمودي
'\single quote  -  علامة اقتباس مفردة
"\Double quote  -  علامة اقتباس مزدوجة
\\Backslash character  -  حرف الخط المائل العكسي
XXX\  الحرف مع Latin-1 لتحديد ترميز من خلال الرجوع الى الوراء بثلاثة ارقام ثمانية XXX ما بين 0 و 377. على سبيل المثال, 251\ هو تسلسل ثماني لرمز حقوق النشر.  
xXX\الحرف مع Latin-1 لتحديد ترميز  من خلال ارقام نظام العد السداسي عشر  XX بين 00 و FF. على سبيل المثال , xA9\ هو تسلسل نظام العد السداسي عشر لرمز حقوق النشر.
uXXXX\الحرف Unicode محدد من خلال اربعة ارقام من نظام العد السداسي عشر  XXXX. على سبيل المثال , u00A9\ هو تسلسل Unicode لرمز حقوق النشر. راجع {{anch("Unicode escape sequences")}}.
u{XXXXX}\كود ال Unicode لتهريب النقطة، على سبيل المثال، u{2F804}\ هي تماما مثل  تهريب اليونيكود نفسه  uD87E\uDC04\
+ +

تهريب الرموز - Escaping characters

+ +

الرموز الخاصة التي لم ترد في الجدول اعلاه، تم تجاهلها، لانها اصبحت  مستنكرة وينبغي تجنبها.

+ +

يمكنك إدراج علامة اقتباس داخل سلسلة حرفية شرط ان يسبقها الرمز backslash. وتعرف هذه العملية بتهريب علامة الاقتباس. على سبيل المثال:

+ +
var quote = "He read \"The Cremation of Sam McGee\" by R.W. Service.";
+console.log(quote);
+
+ +

ونتيجة لذالك سنحصل على السلسلة الحرفية التالية:

+ +
He read "The Cremation of Sam McGee" by R.W. Service.
+
+ +

لتضمين الرمز  backslash نفسه  في سلسلة حرفية، يجب  عليك تهريبه ايضا ب backslash ثانية. وبالتالي سيتحول الى رمز عادي، قابل للقراءة. على سبيل المثال، لتعيين مسار الملف c:\temp الى سلسلة حرفية، استخدم التالي:

+ +
var home = "c:\\temp";
+
+ +

يمكنك ايضا تهريب فواصل الأسطر (line breaks)، وذالك من خلال اضافة backslash في نهاية كل جزء من اجزاء السلسلة الحرفية. الغرض هذه العملية هو الحد من طول التعليمة البرمجية فقط، ولهذا فالسلسلة الحرفية الجديدة، لن تتضمن اي من هذه السلاشات، وكذالك لن تتضمن اية فواصل الأسطر (<line break = <br) المخفية.

+ +
var str = "this string \
+is broken \
+across multiple\
+lines."
+console.log(str);   // this string is broken across multiplelines.
+
+ +

على الرغم من ان جافاسكريبت لا تتوفر عل التعبير "heredoc" المستخدم في كثير من لغات البرمجة الاخرى (php مثلا) والذي يمكتك من التعامل مع السلاسل الحرفية بطريقة مميزة. الا انه من من الممكن تحقيق ما يشبهها من خلال التعبير التالي:

+ +
var poem =
+"Roses are red,\n\
+Violets are blue.\n\
+I'm schizophrenic,\n\
+And so am I."
+
+ +

للمزيد من المعلومات

+ +

تم التركيز في هذا الفصل على اساسيات صياغة الاعلانات والانواع. لدراسة المزيد حول JavaScript language constructs. راجع أيضا الفصول التالية في هذا الدليل:

+ + + +

في الفصل التالي ان شاء الله، سنلقي نظرة على كيفية السيطرة على تدفق البيانات ( control flow constructs ) ومعالجه الأخطاء.

+
+ +

{{PreviousNext("Web/JavaScript/Guide/Introduction", "Web/JavaScript/Guide/Control_flow_and_error_handling")}}

diff --git a/files/ar/web/javascript/guide/index.html b/files/ar/web/javascript/guide/index.html new file mode 100644 index 0000000000..8a2410f634 --- /dev/null +++ b/files/ar/web/javascript/guide/index.html @@ -0,0 +1,116 @@ +--- +title: دليل جافا سكريبت +slug: Web/JavaScript/Guide +tags: + - جافا سكربيت + - دليل +translation_of: Web/JavaScript/Guide +--- +
{{jsSidebar("JavaScript Guide")}}
+ +

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

+ +

الفصول

+ +

هذا الدليل مقسم إلى عدة فصول:

+ + + + + +

{{Next("Web/JavaScript/Guide/Introduction")}}

diff --git a/files/ar/web/javascript/guide/introduction/index.html b/files/ar/web/javascript/guide/introduction/index.html new file mode 100644 index 0000000000..681bb0276a --- /dev/null +++ b/files/ar/web/javascript/guide/introduction/index.html @@ -0,0 +1,159 @@ +--- +title: تقديم +slug: Web/JavaScript/Guide/Introduction +tags: + - جافا سكربيت + - مرشد +translation_of: Web/JavaScript/Guide/Introduction +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide", "Web/JavaScript/Guide/Grammar_and_types")}}
+ +

يقوم هذا الفصل بتقديم جافا سكريبت ويناقش بعض مفاهيمها الأساسية.

+ +

ما يجب أن تعرفه مسبقا

+ +
+

يفترض أن تكون لديك خلفية حول المكونات التالية:

+ + + +

أين تجد المعلومات عن الجافا سكربيت

+ +

وثائق جافا سكربيت على MDN تشتمل على مايلي:

+ + + +

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

+ +

ما هي جافاسكريبت؟

+ +

الجافاسكريبت هي لغة برمجة كائنية التوجة ومتعددة المنصات. هي لغة صغيرة وخفيفة الوزن. داخل بيئة المضيف (على سبيل المثال، متصفح ويب)، في هذه البيئة يمكنك استخدامها على الكائنات.

+ +

تحتوي جافاسكريبت على مكتبة قياسية من الكائنات، مثل Array، Date، وMath، ومجموعة أساسية من العناصر اللغوية مثل العوامل، بنى التحكم، والتصريحات. جوهر جافا سكريبت هو قابليتها للتعامل مع مجموعة متنوعة من الكائنات التي تكون مكملة مع كائنات إضافية. على سبيل المثال:

+ + + +

جافا سكريبت وجافا

+ +

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

+ +

على عكس جافا التي لها نظام المترجم الزمني  compile-time system للاعلان عن الكلاسات، فجافا سكريبت تدعم نظام وقت التشغيل  runtime system ولها بعض أنواع البيانات لتمثيل الأرقام، القيم المنطقية، والسلاسل النصية (و أمور أخرى). تعتمد جافاسكريبت على النموذج الأولي  prototype-based object model لعمل رابط بين الكائنات بينما تستخدم جافا نموذجا أكثر شيوعا يستند إلى الكلاسات class-based object model.  النماذج-البروتوتايبس تسمح بخلق ديناميكية عالية فيما يخص الوراثة. وبالتالي، فإن الخصائص التي يرثها كائن ما، قد تختلف مع مرور الوقت. كما تدعم جافاسكريبت الوظائف دون متطلبات إعلانية خاصة. الوظائف يمكن أن تكون خصائص لكائن،

+ +

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

+ +

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

+ +

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

+ + + + + + + + + + + + + + + + + + + + + + + +
+

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

+
جافا سكربيتجافا
تعتمد على رابط البروتوتايب. لا يوجد تمييز بين أنواع الكائنات. تتم الوراثة من خلال آلية البروتوتايب، ويمكن إضافة الخصائص والوظائف إلى أي كائن حيويتعتمد على الكلاسات (Class-based). وتنقسم الكائنات إلى فئات وحالات، يتم الإرث من خلال التسلسل الهرمي للكلاسات. لا يمكن إضافة الكلاسات والحالات ديناميكيا إلى الخصائص والوظائف.
لا يتم الاعلان عن نوع البيانات المتغيرة (الكتابة ديناميكية).يجب تعريف أنواع البيانات المتغيرة (الكتابة ثابتة).
لا يمكن الكتابة تلقائيا إلى القرص الثابت. +
+
+
+
 
+ +
يمكن الكتابة تلقائيا إلى القرص الثابت.
+
+
+
+ +
+
 
+
+
+ +

لمزيد من المعلومات حول الاختلافات بين جافا سكريبت وجافا، انظر الفصل تفاصيل عن الكائن.

+ +

جافا سكريبت والمواصفات ECMAScript

+ +

 جافا سكريبت موحدة عن طريق Ecma International - الجمعية الأوروبية لتوحيد النظم المعلوماتية والاتصالات (ECMA اختصارا لجمعية مصنعي الكمبيوتر الأوروبية تاريخيا) والتي تنص على لغة برمجة موحدة، هذا الإصدار القياسي من جافا سكريبت، يسمى  ECMAScript. هذا الاصدار، يتصرف بشكل متطابق في جميع التطبيقات المتوافقة مع المعايير. يمكن للشركات استخدام هذه اللغة القياسية لتطوير طريقة تنفيذ جافا سكريبت. يتم توثيق ECMAScript القياسية مع ECMA-262. انظر رؤية جديد جافا سكريبت لمعرفة المزيد عن الاصدارات المختلفة من جافا سكريبت وطبعات مختلفة من مواصفات ECMAScript.

+ +

كما إعتُمِدت ECMA-262 من قبل ISO  المنظمة الدولية للتوحيد القياسي ك ISO-16262.  كما يمكنك أيضا العثور على المواصفات على موقع Ecma International. مواصفات ECMAScript  لا تصف نموذج الكائن المستند  (DOM)، الذي يتم توحيده من قبل اتحاد شبكة الويب العالمية (W3C). وDOM يحدد الطريقة التي تعرض بها كائنات المستند HTML في السكريبت الخاص بك. للحصول على فكرة أفضل حول التقنيات المختلفة التي يتم استخدامها عند البرمجة مع جافا سكريبت، راجع مقالة جافا سكريبت نظرة عامة التكنولوجيات.

+ +

وثائق جافا سكريبت مقابل المواصفات ECMAScript

+ +
+
مواصفات ECMAScript هي مجموعة من المتطلبات لتنفيذ ECMAScript. من المفيد إذا كنت ترغب في تنفيذ ميزات اللغة المتوافقة مع المعايير القياسية في تنفيذ ECMAScript  أو في احدى المحركات SpiderMonkey في فايرفوكس، أو V8 في كروم).
+ +
 
+
+ +

ليس المقصود من مواصفات ال ECMAScript هو دعم برمجة السكريبت. توفر وثائق جافا سكريبت معلومات لكتابة النصوص البرمجية.

+ +

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

+ +

تصف وثائق جافا سكريبت جوانب اللغة التي يمكن استخدامها من قبل مطوري جافا سكريبت.

+ +

الشروع في العمل مع جافا سكريبت

+ +

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

+ +

هناك أداتان هما جزءا من فايرفوكس، وهي مفيدة لتجربة واختبار شفرة جافا سكريبت، هما: وحدة تحكم الويب Console وقائمة جافاسكريبت Scratchpad .

+ +

وحدة تحكم ويب

+ +

وحدة تحكم ويب يعرض لك معلومات عن صفحة الويب التي تم تحميلها حاليا، ويشمل أيضا سطر الأوامر الذي يمكنك استخدامه لتنفيذ اكواد الجافا سكربت في الصفحة الحالية.

+ +

لفتح وحدة تحكم الويب (Ctrl+Shift+K) او F12،  في وحدة التحكم، هناك سطر الأوامر الذي يمكنك استخدامه لادخال اكواد جافا سكريبت، ويظهر الناتج في الجزء أعلاه:

+ +

+ +

المسودة

+ +

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

+ +

لفتح المسودة (Shift+F4)، او حدد "المسودة" من القائمة اختر "المطور"، وهي ضمن القائمة في فايرفوكس. ستفتح في نافذة منفصلة، يمكنك استخدامها لكتابة وتنفيذ جافا سكريبت في المتصفح. يمكنك أيضا حفظ النصوص إلى القرص وتحميلها من القرص.

+ +

+ +

مرحبا بالعالم

+ +

لتبدأ بكتابة جافا سكريبت، افتح المسودة واكتب "مرحبا بالعالم". كما يلي:

+ +
function greetMe(yourName) {
+  alert("Hello " + yourName);
+}
+
+greetMe("World");
+
+ +

من قائمة "تنفيذ" واضغط على تنفيذ او  Ctrl + R لمشاهدة ناتج الكود في المتصفح الخاص بك!

+ +

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

+
+ +

{{PreviousNext("Web/JavaScript/Guide", "Web/JavaScript/Guide/Grammar_and_types")}}

diff --git a/files/ar/web/javascript/guide/loops_and_iteration/index.html b/files/ar/web/javascript/guide/loops_and_iteration/index.html new file mode 100644 index 0000000000..3bc05c57a7 --- /dev/null +++ b/files/ar/web/javascript/guide/loops_and_iteration/index.html @@ -0,0 +1,352 @@ +--- +title: الحلقات والتكرار +slug: Web/JavaScript/Guide/Loops_and_iteration +translation_of: Web/JavaScript/Guide/Loops_and_iteration +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Control_flow_and_error_handling", "Web/JavaScript/Guide/Functions")}}
+ +

الحلقات، وسيلة سريعة وسهلة لفعل شيئا ما، مرارا وتكرارا. يقدم هذا الفصل من دليل الجافاسكريب  مختلف عبارات التكرار المتاحة لجافا سكريبت.

+ +
+

يمكنك التفكير في الحلقة كنسخة من لعبة في الكمبيوتر، حيث ستقوم بتحريك السوبر ماريو X من الخطوات الى الامام، على سبيل المثال، امر التحريك، " تَحرًك ب 5 خطوات إلى الامام". يمكن تطبيق مثل هذه الفكرة باستخدام الحلقة:

+ +
var step;
+for (step = 0; step < 5; step++) {
+  // Runs 5 times, with values of step 0 through 4.
+  console.log('Walking east one step');
+}
+
+ +

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

+ +

الحلقات المتوفرة في جافاسكريبت وهي :

+ + + +

الحلقة for

+ +

الحلقة {{jsxref("statements/for","for loop")}} لاتتوقف عن التكرار حتى يتم تحقق الشرط المحدد ب false. الحلقة for لجافاسكريبت مشابه للحلقة for الخاصة ب Java و C. يوضح الشكل التالي التركيبة الاساسية للحلقة for:

+ +
for ([initialExpression]; [condition]; [incrementExpression])
+  statement
+
+ +

عند تنفيذ الحلقة، يحدث ما يلي:

+ +
    +
  1.  initialExpression : التعبير المستخدم لتهيئة الحلقة، سيتم تنفيذه، إذا كان موجوداً. يقوم هذا التعبير بتهيئة عداد حلقة واحدة أو أكثر، من الممكن استخدام تعبيرات أكثر تعقيدا  إذا لزم الأمر. يمكن ايضا أن يتم تعريف المتغيرات في هذا التعبير.
  2. +
  3. condition : تعبير الشرط الذي تتمحور حوله الحلقة. اذا كانت قيمته تساوي true، ستنفذ الحلقة من جديد، عندما ستصبح قيمته تساوي false، ستنتهي الحلقة، إذا تم حذف تعبير الشرط تماما. سيعتبر الشرط صحيحاً true.
  4. +
  5. statement : التعليمة البرمجية التي ستنفذ ما دام الشرط يساوي true. لتنفيذ تعليمات برمجية متعددة، استخد التعليمة بلوك ({ ... }).
  6. +
  7. incrementExpression : تحديث التعبير، إذا كان موجودا، ينفذ، ويعود التحكم إلى الخطوة رقم 2.
  8. +
+ +

مثال

+ +

تحتوي الدالة التالية على التعليمة for التي تقوم باحصاء عدد العناصر options المحددة في العنصر {{HTMLElement("select")}}. التعليمة for تعلن عن المتغير i وتقوم بتهيئته ب 0. وتتحقق من ان i اصغر من عدد العناصر في العنصر <select>. ستنفذ التعليمة if  بنجاح، وستزيد قيمة i بواحد ما دامت الحلقة مستمرة بالتكرار.

+ +
<form name="selectForm">
+  <p>
+    <label for="musicTypes">Choose some music types, then click the button below:</label>
+    <select id="musicTypes" name="musicTypes" multiple="multiple">
+      <option selected="selected">R&B</option>
+      <option>Jazz</option>
+      <option>Blues</option>
+      <option>New Age</option>
+      <option>Classical</option>
+      <option>Opera</option>
+    </select>
+  </p>
+  <p><input id="btn" type="button" value="How many are selected?" /></p>
+</form>
+
+<script>
+function howMany(selectObject) {
+  var numberSelected = 0;
+  for (var i = 0; i < selectObject.options.length; i++) {
+    if (selectObject.options[i].selected) {
+      numberSelected++;
+    }
+  }
+  return numberSelected;
+}
+
+var btn = document.getElementById('btn');
+btn.addEventListener('click', function() {
+  alert('Number of options selected: ' + howMany(document.selectForm.musicTypes));
+});
+</script>
+
+
+ +

الحلقة do...while

+ +

الحلقة {{jsxref("statements/do...while", "do...while")}} لاتتوقف عن التكرار حتى يتم تحقق الشرط المحدد ب false . يوضح الشكل التالي التركيبة الاساسية للحلقة do...while

+ +
do
+  statement
+while (condition);
+
+ +

statement: تنفذ مرة واحدة قبل أن تبدا عملية التحقق من الشرط. عند البدا بعملية التحقق، اذا كان الشرط (condition) يساوي true، تنفذ التعليمة البرمجية (statement) مرة اخرى. بعد انهاء التنفيذ، يتم التحقق مرة اخرى من الشرط. الى ان يصبح الشرط يساوي false، عندها يتوقف التنفيذ ويتم انتقال التحكم الى التعليمة البرمجية التي تلي do...while. لتنفيذ تعليمات برمجية متعددة، استخدم التعليمة بلوك ({ ... }).

+ +

مثال

+ +

في المثال التالي، الحلقة do، تنفذ مرة واحدة على الاقل وتستمر بالتكرار حتى يصبح i ليس أقل من 5.

+ +
var i = 0;
+do {
+  i += 1;
+  console.log(i);
+} while (i < 5);
+ +

الحلقة while

+ +

الحلقة {{jsxref("statements/while","while")}} ستستمر بتنفيذ التعليمة البرمجية المرتبطة بها طالما الشرط المحدد يساوي true. يوضح الشكل التالي التركيبة الاساسية للحلقة while

+ +
while (condition)
+  statement
+
+ +

عندما سيصبح الشرط يساوي false، ستتوقف التعليمة البرمجية (statement) المرتبطة بالحلقة  عن التنفيذ وسينتقل التحكم الى التعليمة البرمجية التي تلي الحلقة while.

+ +

يتم التحقق من شرط الاختبار قبل تنفيذ statement. كلما عاد الشرط ب true، ستنفذ statement ويتم الرجوع الى الشرط للتحقق منه مرة اخرى. عندما سيعود الشرط ب false سيتوقف التنفيذ وسينتقل التحكم الى التعليمة البرمجية التي تلي الحلقة while.  لتنفيذ تعليمات برمجية متعددة، استخدم التعليمة بلوك ({ ... }).

+ +

المثال الاول

+ +

الحلقة while ستستمر بالتكرار طالما n أقل من ثلاثة:

+ +
var n = 0;
+var x = 0;
+while (n < 3) {
+  n++;
+  x += n;
+}
+
+ +

مع كل تكرار، ستقوم الحلقة بالزيادات على n وتضيف قيمته إلى x. لذالك  x و n ستمتلك القيم التالية:

+ + + +

بعد الانتهاء من المرور الثالث، الشرط ( n < 3 ) لم يعد يساوي true، لذالك ستنتهي الحلقة.

+ +

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

+ +

لتجنب تكرار الحلقة الى ما لا نهاية. تأكد من أن الشرط في الحلقة، سيصبح في نهاية المطاف ب false، التعليمة البرمجية في الحلقة while التالية، لن تتوقف عن التنفيذ بسبب ان الشرط لن يصبح ب false:

+ +
while (true) {
+  console.log('Hello, world!');
+}
+ +
+

تحذير: استمرار تكرار الحلقة الى ما لا نهاية سيتسبب في توقف المتصفحات عن العمل.

+
+ +

التعليمة label

+ +

تستخدم التعليمة {{jsxref("statements/label","label")}}  لتوفير معرف (id) للتعليمة البرمجية المراد الرجوع اليها من موقع آخر في البرنامج. على سبيل المثال، يمكنك استخدام label لتحديد حلقة، ثم استخدام التعليمة break او continue للإشارة إلى ما إذا كان البرنامج ينبغي أن يوقف الحلقة أو الاستمرار في تنفيذها.

+ +

التعبير الخاص بالتعليمة  label يشبه ما يلي:

+ +
label :
+   statement
+
+ +

قيمة label  يمكن ان تكون أي معرف جافاسكريبت باستثناء الكلمات المحجوزة. التعليمة البرمجية (statement) التي سيشار اليها من طرف label يمكن ان تكون اي تعليمة برمجية.

+ +

مثال

+ +

في هذا المثال، label markLoop يعرف الحلقة while.

+ +
markLoop:
+while (theMark == true) {
+   doSomething();
+}
+ +
+

ملاحظة: لمزيد من التفاصيل حول التعليمة label، راجع صفحة مرجع الجافا سكريبت

+
+ +

التعليمة break

+ +

تستخدم التعليمة {{jsxref("statements/break","break")}} لانهاء الحلقة، او switch، أو بالتزامن مع االتعليمة label.

+ + + +

يمكن التعبير عن  التعليمة break من خلال طريقتين:

+ +
break;
+break label;
+
+ +

تستخدم الطريقة الأولى لانهاء الحلقة المتواجدة بها، او لانهاء switch. الطريقة الثانية لانهاء تنفيذ التعليمات التي تم تحديدها من قبل label.

+ +

المثال الاول

+ +

يقوم المثال التالي بالتكرار على عناصر المصفوفة، وبمجرد الوصول الى العنصر المحدد في الشرط وهو theValue سيتم انهاء الحلقة،

+ +
for (var i = 0; i < a.length; i++) {
+  if (a[i] == theValue) {
+    break;
+  }
+}
+ +

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

+ +

المثال التالي، يبين كيفية استخدام التعليمة break بكلا الطريقتين:

+ +
var x = 0;
+var z = 0;
+labelCancelLoops: while (true) {
+  console.log('Outer loops: ' + x);
+  x += 1;
+  z = 1;
+  while (true) {
+    console.log('Inner loops: ' + z);
+    z += 1;
+    if (z === 10 && x === 10) {
+      break labelCancelLoops;
+    } else if (z === 10) {
+      break;
+    }
+  }
+}
+
+ +

التعليمة continue

+ +

يمكن استخدام التعليمة {{jsxref("statements/continue","continue")}} لاستئناف الحلقة while) do-while ،for ، مع labe)، بعد توقفها لغرض معين.

+ + + +

يمكن التعبير عن  التعليمة continue من خلال طريقتين:

+ +
continue;
+continue label;
+
+ +

المثال الاول

+ +

في المثال التالي، لدينا الحلقة while مع التعليمة continue التي ستنفذ حينما تصبح i تساوي 3. ولدينا n الذي سيحتوي على القيم التالية:  1, 3, 7 و 12.

+ +
var i = 0;
+var n = 0;
+while (i < 5) {
+  i++;
+  if (i == 3) {
+    continue;
+  }
+  n += i;
+}
+
+ +

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

+ +

التعليمة label checkiandj تحتوي على التعليمة label checkj. عند مصادفة continue سيقوم البرنامج بانهاء التكرار الحالي ل checkj ويبدأ التكرار من جديد. وفي كل مرة يتم مصادفة continue، تستمر checkj بالتكرار حتى يعود الشرط ب false. عندما سيتم العودة ب false،  ما تبقى من التعليمة checkiandj سيكتمل، و checkiandj ستستمر بالتكرار حتى يعود الشرط ب false. عندما سيتم العودة ب false، سينتقل البرنامج الى التعليمة البرمجية التي تلي checkiandj.

+ +
var i = 0;
+var j = 10;
+checkiandj:
+  while (i < 4) {
+    console.log(i);
+    i += 1;
+    checkj:
+      while (j > 4) {
+        console.log(j);
+        j -= 1;
+        if ((j % 2) == 0) {
+          continue checkj;
+        }
+        console.log(j + ' is odd.');
+      }
+      console.log('i = ' + i);
+      console.log('j = ' + j);
+  }
+ +

عموما: التعليمة break تقوم بانهاء الحلقة نهائيا عندما يتم تحقق الشرط المحدد، فيما تقوم التعليمة continue بتوقيف الحلقة للتحقق من الشرط المحدد، وعندما يتم تنفيذ الشرط، يتم استئناف الحلقة.

+ +

التعليمة for...in

+ +

تستخدم الحلقة {{jsxref("statements/for...in","for...in")}} للتكرار على جميع خصائص الكائن القابلة للتكرار enumerable properties.  مقابل كل خاصية مميزة، ستنفذ الجافا سكريبت تعليمات برمجية محددة. يوضح الشكل التالي التركيبة الاساسية للحلقة for...in

+ +
for (variable in object) {
+  statements
+}
+
+ +

مثال

+ +

الدالة التالية تتضمن كائن واسم الكائن كبارامترات لها. تقوم بالتكرار على كل خصائص الكائن وترجع سلسلة نصية بأسماء الخصائص والقيم الخاصة بها.

+ +
function dump_props(obj, obj_name) {
+  var result = '';
+  for (var i in obj) {
+    result += obj_name + '.' + i + ' = ' + obj[i] + '<br>';
+  }
+  result += '<hr>';
+  return result;
+}
+ +

بالنسبة للكائن car مع الخصائص make و model، الناتج سيكون على الشكل التالي:

+ +
car.make = Ford
+car.model = Mustang
+
+ +

for...in و المصفوفات

+ +

على الرغم من كونه مغريا استخدام الحلقة for...in للتكرار على عناصر المصفوفة {{jsxref("Array")}}  الا انها، يمكن أن تقوم بسلوك غير متوقع. في الواقع، الحلقة for...in ستقوم بإرجاع اسماء الخصائص المعرفة من قبل المستخدم بالإضافة إلى الفهارس الرقمية. فمثلا، إذا قمت بالتعديل على Array object، كإضافة خصائص او وظائف جديدة. فستقوم الحلقة for...in بالتكرار على هذه الخصائص او الوظائف بالإضافة إلى عناصر المصفوفة، وبالتالي فمن الأفضل استخدام الحلقة التقليدية {{jsxref("statements/for","for")}} لارجاع الفهارس الرقمية بشكل صحيح عند التكرار على المصفوفة.  يبين المثال التالي كيفية حصول ذالك.

+ +
var myArray = [0, 1, 2, , , 5];
+myArray.foo = "hello";
+
+for (var i in myArray) {
+  	console.log(i);  // Outputs 0, 1, 2, 5, hello.
+}
+
+for (var i = 0; i < myArray.length; ++i) {
+  	console.log(i);  // Outputs 0, 1, 2, 3, 4, 5
+}
+ +

الحلقة for...of

+ +

التعليمة {{jsxref("statements/for...of","for...of")}} نوع جديد من الحلقات تم إضافتها الى الإصدار السادس  من جافا سكربت ، وتستخدم للتكرار على العناصر الموجودة في أي مجموعة أو iterable objects (مثل {{jsxref("Array")}}, {{jsxref("Map")}}, {{jsxref("Set")}} والكائن {{jsxref("functions/arguments","arguments")}} الخ.), كما أن هذا الأسلوب يمكننا من تنفيذ تعليمة برمجية معينة على كل عنصر تم جلبه على حدة للتعديل على أي من خصائصه. يوضح الشكل التالي التركيبة الاساسية للحلقة for...of

+ +
for (variable of object) {
+  statement
+}
+ +

المثال التالي، يوضح الفرق بين الحلقة for...of والحلقة  {{jsxref("statements/for...in","for...in")}} الحلقة for...in تقوم بارجاع اسماء الخصائص فيما الحلقة for...of تقوم بارجاع قيم الخصائص:

+ +
let arr = [3, 5, 7];
+arr.foo = 'hello';
+
+for (let i in arr) {
+   console.log(i); // logs "0", "1", "2", "foo"
+}
+
+for (let i of arr) {
+   console.log(i); // logs 3, 5, 7
+}
+
+
+ +

{{PreviousNext("Web/JavaScript/Guide/Control_flow_and_error_handling", "Web/JavaScript/Guide/Functions")}}

diff --git a/files/ar/web/javascript/guide/regular_expressions/index.html b/files/ar/web/javascript/guide/regular_expressions/index.html new file mode 100644 index 0000000000..96928196f8 --- /dev/null +++ b/files/ar/web/javascript/guide/regular_expressions/index.html @@ -0,0 +1,813 @@ +--- +title: التعبيرات القياسية +slug: Web/JavaScript/Guide/Regular_Expressions +translation_of: Web/JavaScript/Guide/Regular_Expressions +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Text_formatting", "Web/JavaScript/Guide/Indexed_collections")}}
+ +

التعبيرات القياسية (Regular Expressions)، هي أنماط (patterns) تُستخدم لمطابقة مجموعة من الأحرف في السلاسل النصية. التعبيرات القياسية في جافاسكربت كائنات أيضا. تُستخدم هذه الأنماط مع الوظائف {{jsxref("RegExp.exec", "exec")}} و{{jsxref("RegExp.test", "test")}} للكائن {{jsxref("RegExp")}}، ومع الوظائف {{jsxref("String.match", "match")}}، و {{jsxref("String.replace", "replace")}}، و{{jsxref("String.search", "search")}} و {{jsxref("String.split", "split")}} للكائن {{jsxref("String")}}. يتناول هذا الفصل  تعبيرات جافاسكربت القياسية.

+ +
+

انشاء تعبير قياسي او ريجكس

+ +

يمكنك انشاء ريجكس من خلال احدى الطرق التالية:

+ +

الطريقة الاولى، باستخدام التعبير القياسى الحرفي regular expression literal، ويتضمن الباترن pattern بين سلاشين، كما يلي:

+ +
var re = /ab+c/;
+ +

يقوم ال Regular expression literals بتجهيز التعبير القياسي عند تحميل السكريبت. شرط ان يظل التعبير القياسي ثابتا، في هذه الحالة، استخدام هذا الشكل المختصر يمكن أن يحسن من الأداء.

+ +

الطريقة الثانية، من خلال استدعاء constructor الكائن RegExp، كما يلي:

+ +
var re = new RegExp('ab+c');
+ +

استخدام ال constructor، يقلل من وقت تشغيل الريجكس. إسْتخدِم ال  constructor عندما تريد ان يكون الريجكس قابلا للتغيير، او في حالة عدم علمك بالريجكس الذي ستحصل عليه من طرف اخر. كحقل المدخلات مثلا.

+ +

انشاء باترن الريجكس

+ +

يتكون الباترن البسيط اما من رموز عادية، مثل /abc/، او خليط من الرموز العادية والرموز الخاصة، مثل /ab*c/ او /Chapter (\d+)\.\d*/. يحتوي هذا الباترن على اقواس هلالية، هذه الاقواس ستقوم بدور ذاكرة الجهاز، بحيث ستقوم بتخزين قيمة المطابقة الناتجة عن هذا الجزء من الباترن وفهرستها ليتم استدعاؤها لاحقا. للمزيد من التفاصيل حول مطابقة السلسلة النصية الجزئية بين قوسين.

+ +

استخدام الباتر البسيط

+ +

تتكون الباترنز البسيطة، من رموز صريحة ومباشرة، تصف فيها ما تريد مقارنته مباشرة. مثلا، الباترن /abc/ سيطابق مجموعة من الرموز في سلسلة نصية، شرط تواجد هذه الرموز جنبا الى جنب بشكل مرتب. لذالك، ستنجح المطابقة في هذه السلسلة النصية "Hi, do you know your abc's?"  وكذالك في السلسلة النصية التالية "The latest airplane designs evolved from slabcraft."، نجحت المطابقة في كلتا الحالتين لان السلسلة الفرعية 'abc' هي المطلوبة. وهذا لايتطابق مع هذه السلسلة النصية 'Grab crab' لانها تحتوي على سلسلة نصية غير تلك المطلوبة  'ab c'.

+ +

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

+ +

عندما يتطلب الامر عملية بحث، أكثر من مطابقة صريحة ومباشرة، مثل البحث عن واحد او اكثر من ال 'b'، او البحث عن مسافة فارغة، عندها سيتوجب على الباترن ان يحتوي على الرموز الخاصة. مثلا، الباترن /ab*c/ سيطابق مجموعة من الرموز، حيث ستكون 'a' متبوعة بصفر او اكثر من ال 'b'، الرمز الخاص نجمة * يرصد وجود العنصر المطلوب صفر او اكثر من المرات، متبوعا مباشرة ب 'c'. بعد فحص السلسلة النصية "cbbabbbbcdebc," قام الباترن بمطابقة السلسلة الجزئية 'abbbbc'.

+ +

يحتوي الجدول التالي على قائمة مكتملة من رموز الريجكس الخاصة وشرحها.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

الرموز الخاصة بالريجكس.

+
الرمزشرح الاستخدام
\ +

 

+ +

مطابقات وفقا للقواعد التالية:
+
+ الباكسلاش الذي يسبق الرمز العادي يشير الى ان الرمز التالي هو رمز من الرموز الخاصة ولا ينبغي تفسيره حرفيا. مثلا 'b' من دون باكسلاش \ ، ستطابق 'b' بحروف صغيرة. لكن \b في حد داتها لا تطابق اي حرف، لانها من الرموز الخاصة وتعني حصر او تحديد حدود للرموز المطلوبة word boundary character.
+
+ الباكسلاش الذي يسبق الرموز الخاصة، يشير الى ان الرمز التالي هو ليس من الرموز الخاصة وينبغي تفسيره حرفيا. مثلا، الباترن /a*/ يحتوي على احد الرموز الخاصة * وهو لمطابقة صفر او اكثر من a، بعد اضافة الباكسلاش له، كما في  الباترن /a\*/ تم الغاء رمزيتة، وبالتالي اصبح الباترن  /a\*/ يطابق السلسلة الحرفية 'a*'.
+
+ لا تنس تهريب الباكسلاش نفسه، بينما تستخدم الكونستراكتر RegExp( "\\s", "g" )، لانه يعمل ايضا، كمهرب للرموز الخاصة في السلسلة النصية.

+ +

 

+
^ +

 

+ +

مطابقة بداية المدخلات. ادا كان البند multiline ب true، اي ان m موجودة في الباترن /^a/gm سيبدا البحث عن المطابقة في بداية اي سطر جديد.
+
+ مثلا الباترن  /^a/gm  سيطابق اثنان من 'a'، في "a special char\nacter"، لاحظ وجود السطر الجديد \n في السلسلة النصية.
+
+ الرمز ^ سيصبح له معنى اخر عندما يستخدم مع المجموعة. توجه الى مجموعة الرموز لمعرفة المزيد من التفاصيل.

+ +

 

+
$ +

 

+ +

مطابقة نهاية المدخلات. ادا كان البند multiline  ب true، اي ان m موجودة في الباترن /r$/gm سيبدا البحث عن المطابقة في نهاية اي سطر جديد.
+
+ مثلا الباترن /r$/gm سيطابق اثنان من 'r'، في "a special char\nacter"، لاحظ وجود السطر الجديد \n في السلسلة النصية.

+
* +

 

+ +

مطابقة التعبير الذي سيسبق الرمز * صفر او اكثر من المرات، وهو مكافئ ل {0,}.

+ +

مثلا، /bo*/ سيطابق 'boooo' في "A ghost booooed" و 'b' في "A bird warbled" لكن لا شئ بالنسبة ل "A goat grunted".

+ +

 

+
+ +

 

+ +

مطابقة التعبير الذي سيسبق الرمز + مرة واحدة على الاقل او اكثر من المرات، وهو مكافئ ل {1,}.

+ +

مثلا، /a+/ ستطابق 'a' في "candy" ومجموعة ال  'a' في "caaaaaaandy" لكن لا شئ بالنسبة ل "cndy".

+ +

 

+
? +

 

+ +

مطابقة التعبير الذي سيسبق الرمز ? صفر او واحد من المرات، وهو مكافئ ل {0,1}.
+
+ مثلا، الباترن /e?le?/ سيطابق 'el' في "angel" و 'le' في "angle" وكذالك 'l' في "also".
+
+ اذا استخدم الرمز ? مباشرة بعد احد هذه المحددات *، +، ?، او {}، سيؤثر على سلوكها الافتراضي، فيجعلها غير طماعة non-greedy او غير جشعة (تطابق عدد محدود من الاحرف) بخلاف سلوكها الافتراضي، وهو التصرف بجشع (تطابق اكثر عدد ممكن من الاحرف)، مثلا، باستخدام الباترن الجشع، /\d+/ ستطابق كل السلسلة "123" في "123abc" . اما باستخدام الباترن الغير جشع، /\d+?/ وعلى نفس السلسلة ستطابق "1" فقط.
+
+ مثال اكثر دقة حول non-greedy و greedy، فرضا، نريد مطابقة تاجات الاتش تي ام ال، باستخدام الباترن الجشع /<(.+)>/g سيتم مطابقة كل السلسلة النصية "<div>fCh<p>elema</p>lCh</div>"، اما باستخدام الباترن الغير شجع /<(.+?)>/g فسيتم مطابقة التاجات ومحتواها فقط. بمعنى، ان العملية ستسير بالشكل التالي: مع بداية البحث، عندما سيجد التاج الاول '<div>' سييكتفي به ولا يطمع في ما يليه، ثم ينتقل مباشرة نحو الهدف الثاني '<p>' فيطابقه ويكتفي به دون ان يطمع في ما يليه، وهكذا. مع العلم ان الباترن عبارة عن البحث (.+?) في كل شئ، لكن من دون طمع.
+ الرمز ? يصبح له معنى اخر مع lookahead assertions، النظر الى الامام x(?=y) ومنع النظر الى الامام x(?!y) سيتم شرحها في هذا الجدول.

+ +

 

+
. +

 

+ +

النقطة الكسرية تطابق اي شئ، ما عدا السطر الجديد

+ +

مثلا، /.n/ ستطابق 'an' و 'on' في "nay, an apple is on the tree", لكن ليس 'nay'.

+ +

 

+
(x) +

 

+ +

مطابقة 'x' وانشاء فهرسة جزئية. كما يبين المثال التالى. اقواس المجموعة المفهرسة تسمى capturing parentheses.
+
+ مثلا،'(foo)' و '(bar)' في الباترن /(foo) (bar) \1 \2/ تطابق وتفهرس الكلمة الاولى والكلمة الثانية في السلسلة الحرفية "foo bar foo bar". والفهرسة الرقمية \1 و \2  تولد الكلمة الثالثة والكلمة الرابعة بناءا على الاقواس المحيطة بكل منهما. تذكر ان هذه الفهرسة الرقمية تستخدم داخل الباترن فقط. فيما تستخدم المتغيرات السحررية $1, $2, ..., $n خارج الباترن، وتستخدم في عملية الاستبدال فقط، مثلا، 'bar foo'.replace(/(...) (...)/, '$2 $1').  $& يطابق هذا المتغير السحري $& السلسلة النصية بالكامل، او بمعنى اصح، ينقل ناتج الباترن بالكامل.

+ +

 

+
(x:?) +

 

+ +

مطابقة ال 'x' لكن دون انشاء جزئية مفهرسة، اقواس المجموعة هنا تسمى non-capturing parentheses

+ +

انشاء جزئية مفهرسة وعدم استخدامها، يبطئ من سرعة محرك الريجكس، لانه يتسبب له في عمل زائد، يمكنك جعل محرك الريجكس اسرع قليلا باستخدام non-capturing.

+ +

علامة الاستفهام والنقطتين بعد قوس الافتتاح هما من الرموز الخاصة، استخدامهما جنبا الى جنب يخبر محرك الريجكس بان هذه المجموعة لا ينبغي ان تعامل كجزئية مفهرسة. وبالتالي لا يمكن، استدعاء المطابقة من خلال الفهرسة الرقمية\1... او عناصر المصفوفة [1]... او اعادة استخدام المطابقة من خلال المتغيرات السحرية $1...$9.

+ +

 

+
=? +

 

+ +

مطابقة ال 'x' فقط اذا كانت 'x' متبوعة ب 'y'. وهذا يسمى النظر الى الامام lookahead.

+ +

مثلا، /Jack(?=Sprat)/ سيطابق 'Jack' فقط اذا كان متبوعا ب 'Sprat'. وكذالك بالنسبة ل /Jack(?=Sprat|Frost)/ سيطابق 'Jack' فقط اذا كان متبوعا ب 'Sprat' او 'Frost'. ومع ذالك، لا 'Sprat' ولا 'Frost' جزء من ناتج المطابقة.

+ +

 

+
!? +

 

+ +

مطابقة ال 'x' فقط اذا كانت 'x' غير متبوعة ب 'y'. وهذا يسمى منع او ابطال النظر الى الامام negated lookahead.

+ +

مثلا، /\d+(?!\.)/ سيطابق عدد فقط اذا كان غير متبوعا بفاصلة كسرية. الريجكس /\d+(?!\.)/.exec("3.141") سيطابق '141' لكن لن يطابق '3.141'.

+ +

 

+
x|y +

 

+ +

مطابقة 'x' أو 'y'.

+ +

مثلا، /green|red/ سيطابق 'green' في "green apple" و 'red' في "red apple.".

+ +

 

+
{n} +

 

+ +

مطابقة n تحديدا، بناءا على التعبير الذي سيسبقه. n يجب ان يكون عددا صحيحا.
+
+ مثلا، /a{2}/ لن يطابق 'a'في "candy," لكنه سيطابق جميع ال a في "caandy," كما سيطابق اثنان من ال a الاولى في "caaandy.".

+ +

 

+
{n,} +

 

+ +

مطابقة n او اكثر، بناءا على التعبير الذي سيسبقه. n يجب ان يكون عددا صحيحا.

+ +

مثلا، /a{2,}/ سيطابق "aa" ، "aaaa" و "aaaaa" لكن ليس "a".

+ +

 

+
{n,m} +

 

+ +

حيث ان n و m من الاعداد الصحيحة الموجبة، و n <= m. فستكون المطابقة من n الى m، بناءا على التعبير الذي سيسبقها.

+ +

مثلا، /a{1,3}/ لن يطابق شئ في "cndy" لكنه سيطابق 'a' في "candy," وكذاك اثنان من ال 'a' الاولى في "caandy," وايضا الثلاثة "a" الاولى في "caaaaaaandy". لاحظ عند مطابقة "caaaaaaandy" تم مطابقة "aaa" فقط، بالرغم من احتواء السلسة النصية على اكثر من ذالك.

+ +

 

+
[xyz] +

 

+ +

المجموعة، او مجموعة الرموز، هذا النوع من الباترن يطابق اي رموز داخل الاقواس المعقوفة، بما فيها المهربات المتتالية escape sequences. الرموز الخاصة مثل النقطة (.) والنجمة (*) تصبح رموز عادية شانها شان اي حرف في سلسلة نصية، لذالك فهي لا تحتاج لباكسلاش. يمكنك تحديد منظم الرموز وفصله بشرطة، كما يبين المثال التالي:
+
+ الباترن [a-d] سيطابق نفس ما سيطابقه الباترن [abcd] سيطابقان 'b' في "brisket" و 'c' في "city". وكذالك بالنسبة للباترن /[a-z.]+/ و /[\w.]+/ بامكانهما مطابقة كامل السلسلة النصية "test.i.ng".

+ +

 

+
[xyz^] +

 

+ +

منع مجموعة من الرموز او رموز معينة. سيتم مطابقة اي شئ ما عد ما ورد داخل الاقواس المعقوفة، يمكنك تحديد منظم الرموز وفصله بشرطة، جميع ما يمكن استخدامه في المجموعة او مجموعة الرموز العادية يمكن استخدامه هنا.

+ +

مثلا، الباترن [^abc] هو نفسه [^a-c]. سيطابقان 'r' في "brisket" و 'h' في "chop."

+ +

 

+
[b\] +

 

+ +

سيطابق backspace (U+0008). اذا كنت ترغب بمطابقة الرمز النصي: رجوع الى الخلف literal backspace character. فمن الضروري استخدام الاقواس المعقوفة، حتى لا تتعارض مع \b.

+ +

 

+
b\ +

 

+ +

مطابقة حدود الكلمة word boundary.

+ +

\b، ستطابق الكلمة التي لايسبقها ولا يليها اي من، ما ورد في هذه المجموعة [A-Za-z0-9_] او في مثيلتها \w، بمعنى ادق، ستقبل بوجود المسافة الفارغة والرموز النصية الخاصة مثل "&=)é'?*-" ، اي، كل ما يمكن ان ينتج عن هذه المجموعة [^A-Za-z0-9_] او عن مثيلتها \W، اما من قبل او من بعد المطابقة، او من كلا الجانبين، او ان تكون في بداية السلسلة او نهايتها. لاحظ ان ال \b ليست جزءا من المطابقة. بل للدلالة فقط. وايضا لا تتعارض مع [\b].

+ +

امثلة مختلفة:
+
+ /\bm/ ستطابق 'm' في "moon".
+ /oo\b/ لن تطابق 'oo' في "moon" لان 'oo' متبوعة بالكلمة الرمزية 'n'.
+ /oon\b/ ستطابق 'oon' في "moon"، لان 'oon' هو نهاية السلسلة النصية، وبالتالي ليست متبوعة باية كلمة رمزية.
+ /\w\b\w/ لن يطابق اي شئ، لان \w لايمكنها ابدا ان تكون متبوعة ب \b و \w.

+ +
+

ملاحظة: محرك الريجكس في الجافاسكريبت حدد بالتدقيق مجموعة الرموز على ان تكون "كلمات" رمزية. أي حرف ليس في تلك المجموعة يعتبر كلمة مكسورة. هذه المجموعة من الأحرف محدودة إلى حد ما: وهي تتألف فقط من الأبجدية الرومانية في كلتا الحروف الصغيرة والحروف الكبيرة، والاعداد العشرية، والرمز underscore. الحروف المعلمة مثل "é" او "ü" ، لسوء الحظ عوملت ككلمات مكسورة.

+ +

 

+
+
B\ +

 

+ +

ال non-word boundary\B. عكس ما يمكن لل \b ان تقوم به.

+ +

مثلا، /\B../ ستطابق 'oo' في "noonday"، /y\B./ ستطابق 'ye' في "possibly yesterday".

+ +

 

+
cX\ +

 

+ +

حيث ان X هو منظم الرموز من A الى Z. يطابق رمز عنصر التحكم في سلسلة نصية. مثلا،

+ +

مثلا، /\cM/ سيطابق control-M (U+000D) في السلسلة النصية.

+ +

 

+
d\ +

 

+ +

مطابقة الاعداد. ويكافئ الباترن [0-9].

+ +

مثلا، /\d/ او /[0-9]/ ستطابق '2' في "B2 is the suite number.".

+ +

 

+
D\ +

 

+ +

مطابقة كل شئ ما عدا الاعداد. ويكافئ الباترن [^0-9].

+ +

مثلا، /\D/ او /[^0-9]/ سيطابق 'B' في "B2 is the suite number.".

+ +

 

+
f\سيطابق نموذج التلقيم form feed (U+000C).
n\سيطابق سطر التلقيم line feed (U+000A).
r\ +

سيطابق carriage return (U+000D).

+
s\ +

 

+ +

مطابقة رمز المسافة الفارغة، بما في ذالك المسافة، التاب، نمودج التلقيم، سطر التلقيم، ويكافئ [ \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff].

+ +

مثلا، /\s\w*/ سيطابق ' bar' في "foo bar."

+ +

 

+
S\ +

 

+ +

مطابقة اي شئ ما عدا رمز المسافة الفارغة، ويكافئ [^ \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff].

+ +

مثلا، /\S*/ سيطابق 'foo' في "foo bar."

+ +

 

+
t\سيطابق tab (U+0009).
v\ +

سيطابق vertical tab (U+000B).

+
w\ +

 

+ +

مطابقة الحروف الابجدية بما في ذالك ال underscore. ويكافي [A-Za-z0-9_].

+ +

مثلا، /\w/ سيطابق 'a'في "apple," و '5' في "$5.28," و '3' في "3D."

+
W\ +

 

+ +

مطابقة اي شئ غير الحروف الابجدية والاندرسكور، ويكافئ [^A-Za-z0-9_].

+ +

مثلا، /\W/ او /[^A-Za-z0-9_]/ سيطابق '%' في "50%.".

+ +

 

+
n\ +

 

+ +

حيث ان n عدد صحيح موجب، سيشير الى المجموعة المفهرسة capturing parentheses .

+ +

مثلا، /apple(,)\sorange\1/ سيطابق 'apple, orange,' في "apple, orange, cherry, peach.".

+ +

 

+
0\ +

 

+ +

مطابقة الرمز NULL (U+0000). لا تتبع هذا برقم آخر، بسبب ان \0<digits> هو تسلسل التهريب الثماني استخدم \x00 بدلا منه.

+ +

 

+
xhh\مطابقة الرمز مع الكود hh (two hexadecimal digits).
uhhhh\مطابقة الرمز مع الكود hhhh (four hexadecimal digits).
u{hhhh}( فقط عندما يستخدم u flag ) سيطابق الرمز مع ال Unicode بالقيمة hhhh (hexadecimal digits).
+ +

  لتهريب تعابير الريجكس في المدخلات النصية، يمكنك  استخدام دالة الاستبدال التالية:

+ +
function escapeRegExp(string) {
+  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
+}
+ +

يستخدم البند g بعد الباترن، لاجراء بحث عام، ينظر في كل السلسلة النصية ويعود بكل المطابقات. تم شرحه بالتفصيل ادناه. البحث المتقدم باستخدام البنود.

+ +

استخدام الاقواس

+ +

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

+ +

مثلا، الباترن /Chapter (\d+)\.\d*/ يطابق بدقة، الرموز 'Chapter ' متبوعة بواحد او اكثر من الارقام (\d تشير الى اي رقم و + تشير الى واحد او اكثر من المرات، بالاضافة الى الاقواس المستخدمة خصيصا لتخزين وفهرسة ما سينتج عنه )، متبوعا بنقطة او فاصلة عشرية التي هي نفسها من الرموز الخاصة، يسبقها الباكسلاش \ الذي بدوه يخبر الباترن بان يعاملها كنقطة عادية، متبوعا باي رقم يكرر صفر او اكثر من المرات (\d تشير الى اي رقم والنجمة * تشير الى صفر او اكثر من المرات).

+ +

هذا الباترن سيطابق "Chapter 4.3" في "Open Chapter 4.3, paragraph 6"، وايضا سيقوم بتخزين وفهرسة الجزئية '4'. بينما الباترن لا يطابق شئ في "Chapter 3 and 4" بسبب ان السلسلة الحرفية لاتحتوي على النقطة بعد الرقم '3'.

+ +

لمطابقة سلسلة فرعية من دون التسبب في فهرسة الجزء المتطابق (راجع non-capturing)، ضمن الاقواس ابدا الباترن ب ?:. مثلا (?:\d+) ستطابق واحد او اكثر من الارقام من دون ان تفهرس الرموز المتطابقة.

+ +

العمل مع الريجكس

+ +

تستخدم التعابير القياسية مع اثنين من الاوبجكت. الاوبجكت الاول هو RegExp ويحتوي على الوظيفتين test و exec والاوبجكت الثاني وهو String ويحتوي على الوظائف التالية: match، replace، search، و split.  تم شرح هذه الوظائف بالتفصيل في JavaScript reference.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

الوظائف المملوكة للكائن RegExp

+
الوظيفةوصفها
exec تقوم هذه الوظيفة بتنفيذ بحث لمطابقة سلسلة نصية. وتعود بمصفوفة تحتوي على نتيجة البحث، او تعود ب null في حالة عدم المطابقة.
test تقوم هذه الوظيفة بعمل فحص لمطابقة سلسلة نصية. وتعود اما ب true او false.
match تقوم هذه الوظيفة بتنفيذ بحث لمطابقة سلسلة نصية. وتعود بمصفوفة تحتوي على نتيجة البحث، او تعود ب null في حالة عدم المطابقة. (نفس ما تقوم به الوظيفة exec).
search تقوم هذه الوظيفة بعمل فحص لمطابقة سلسلة نصية. وتعود برقم المكان الذي يتواجد فيه ما تمت مطابقته. او ب -1 في حالة لم يتم العثور على المطلوب.
replace تقوم هذه الوظيفة بتنفيذ بحث لمطابقة سلسلة نصية. ويحل محل السلسلة الجزئية المتطابقة، السلسلة الجزئية البديلة.
split هذه الوظيفة تستخدم الريجكس او سلسلة نصية ثابتة لتقسيم السلسلة الى مصفوفة من السلاسل الجزئية.
+ +

عندما تريد معرفة ما اذا كان الباترن موجود في سلسلة نصية ام لا، استخدم اما الوظيفة test او الوظيفة search ، اما لمعرفة المزيد من المعلومات (ولكن أبطأ قليلا في التنفيذ)، استخدم اما الوظيفة exec او الوظيفة match اذا استخدمت exec او match ونجحت المطابقة، فان هاتان الوظيفتان ستعود بمصفوفة، وفي نفس الوقت ستقوم بتحديث خصائص الريجكس المرتبطة به وكذلك خصائص الريجكس RegExp. اذا فشلت المطابقة, ستعود الوظيفة exec ب null ( التي تفرض : false).

+ +

في المثال التالي، السكريبت يستخدم الوظيفة exec للبحث عن مطابقة في السلسلة النصية:

+ +
var myRe = /d(b+)d/g;
+var myArray = myRe.exec('cdbbdbsbz');
+ +

إذا كنت لا تحتاج إلى الوصول إلى خصائص الريجكس، هناك طريقة بديلة لإنشاء myArray، كالتلي:

+ +
var myArray = /d(b+)d/g.exec('cdbbdbsbz'); // similar to "cdbbdbsbz".match(/d(b+)d/g); however,
+    // the latter outputs Array [ "dbbd" ], while
+    // /d(b+)d/g.exec('cdbbdbsbz') outputs Array [ "dbbd", "bb" ].
+    // See below for further info (CTRL+F "The behavior associated with the".)
+ +

إذا كنت ترغب في بناء ريجكس من سلسلة نصية، هناك بديل آخر، كالتالي:

+ +
var myRe = new RegExp('d(b+)d', 'g');
+var myArray = myRe.exec('cdbbdbsbz');
+ +

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

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

نتائج تنفيذ الريجكس

+
الكائنالخاصية او الفهرسالوصففي هذا المثال
myArray السلسلة النصية التي جرى مطابقتها وجميع السلاسل النصية الجزئية المفهرسة.['dbbd', 'bb', index: 1, input: 'cdbbdbsbz']
indexفهرس بداية المُطابَقة في السلسلة النصية، والفهرسة تبتدئ من 0.1
inputالسلسلة النصية الأصلية."cdbbdbsbz"
[0]الرموز الاخيرة التي جرى مطابقتها"dbbd"
myRelastIndexالفهرس الذي ستبدأ عنده عملية البحث عن المطابقة التالية. وإذا لم يتم ضبط البند "g" فستبقى قيمته مساويةً للصفر. للمزيد حول البحث المتقدم باستخدام البنود.5
sourceنص الباترن. تم تحديثه في الوقت الذي تم فيه إنشاء الريجكس، وليس وقت تنفيذه."d(b+)d"
+ +

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

+ +
var myRe = /d(b+)d/g;
+var myArray = myRe.exec('cdbbdbsbz');
+console.log('The value of lastIndex is ' + myRe.lastIndex);
+
+// "The value of lastIndex is 5"
+ +

بينما يوضح المثال التالي كيفية الوصول الى خصائص الكائن بالطريقة الخاطئة:

+ +
var myArray = /d(b+)d/g.exec('cdbbdbsbz');
+console.log('The value of lastIndex is ' + /d(b+)d/g.lastIndex);
+
+// "The value of lastIndex is 0"
+ +

حاصل الباترن /d(b+)d/g في كلتا التعليمات البرمجية، عبارة عن كائنان مختلفان، لذالك هما مختلفان في قيمة الخاصية lastIndex اذا كنت ترغب في الوصول الى خصائص الريجكس المنشا من طرف معد او مهيئ الاوبجكت، يلزمك اولا اسناده لمتغير.

+ +

Using parenthesized substring matches

+ +

بمجرد تضمين جزء من الباترن داخل الاقواس الهلالية، سيصبح جزءا مفهرسا قابل لاعادة الاستخدام، مثلا،  الباترن /a(b)c/ سيطابق 'abc' في  "abcd" ويفهرس المطابقة الجزئية (b) برقم 1، ناتج المطابقة الجزئية (b) هو السلسلة الحرفية الجزئية 'b'. لاستدعاء هذا الجزء المفهرس خارج الباترن، استخدم عناصر المصفوفة [1].... ولاعادة استخدامها داخل الباترن استخدم الفهرسة الرقمية \1 ....
+ - كيفية استدعائها خارج الباترن:

+ +
var myRe = /a(b)c/;
+var myArray = myRe.exec('abcb');
+console.log('The result of submatch N1: ' + myArray[1] );
+
+// log: The result of submatch N1: b
+ +

يمكنك استخدام عدد لا متناهي من هذه الاجزاء المفهرسة، تبتدئ الفهرسة من واحد، عائد المصفوفة سيتضمن جميع الاجزاء المفهرسة في الباترن.
+ كيفية اعادة استخدامها داخل الباترن:

+ +
var myRe = /a(b)c\s\1/g;
+var myArray = myRe.exec('abc b');
+console.log('The result of submatch N1: ' + myArray[1] );
+
+// log: The result of submatch N1: b
+ +

يستخدم السكريبت التالي الوظيفة ()replace لعكس الكلمتين John و Smith في السلسلة النصية 'John Smith'. ويستخدم في نص الاستبدال، المتغيرات السحرية $1 و $2 لاستدعاء المطابقة الجزئية المفهرسة الاولى والثانية. مثال:

+ +
var re = /(\w+)\s(\w+)/;
+var str = 'John Smith';
+var newstr = str.replace(re, '$2, $1');
+console.log(newstr);
+
+// "Smith, John"
+ +
+

ملاحظة: يسمح باستخدام المتغيرات السحرية، 9 مرات فقط، في العملية الواحدة.

+
+ +

البحث المتقدم باستخدام البنود

+ +

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

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

بنود الريجكس

+
FlagDescription
gبحث عام، عدم وجوده = النتيجة الاولى فقط.
iعدم مراعاة حالة الاحرف، سواء كانت صغيرة او كبيرة.
mالبحث في السطور المتعدد = كامل النص.
uسلسلة يونيكود، أي معاملة الباترن على أنه سلسلة من رموز يونيكود (Unicode code points).
yالمطابقة ستبدأ من الفهرس المُشار إليه بالخاصية lastIndex لكائن التعابير النمطية في السلسلة الهدف، ولن تتم محاولة مطابقة ما قبل هذا الفهرس. للمزيد من المعلومات sticky
+ +

لتضمين بند مع الريجكس استخدم التعبير التالي:

+ +
var re = /pattern/flags;
+ +

او

+ +
var re = new RegExp('pattern', 'flags');
+ +

البنود، جزء لا يتجزأ من الريجكس. لا يمكن إزالتها أو إضافتها لاحقا.

+ +

مثلا، re = /\w+\s/g يقوم بانشاء ريجكس يبحث على واحد او اكثر من الرموز متبوعة بمسافة واحدة، يقوم بتنفيذ هذا الاجراء على السلسلة الحرفية (كاملة = g):

+ +
var re = /\w+\s/g;
+var str = 'fee fi fo fum';
+var myArray = str.match(re);
+console.log(myArray);
+
+// ["fee ", "fi ", "fo "]
+ +

يمكنك استبدال هذا السطر:

+ +
var re = /\w+\s/g;
+ +

ب:

+ +
var re = new RegExp('\\w+\\s', 'g');
+ +

وستحصل على نفس النتيجة.

+ +

يستخدم  البند m لاخبار محرك الريجكس، بان المدخلات النصية، المتعددة السطور، يجب ان تعامل كسطور متعددة. اذا تم استخدام البند m فسيتطابق الرمزان الخاصان ^ و $ ، مع بداية أو نهاية كل سطر من المدخلات، بدلا من المدخل بالكامل. مثال:

+ +
var re = /^Multi\s*line$/gm;
+var str = 'Multi line\n or \nMultiline';
+var myArray = str.match( re );
+
+console.log( myArray );
+// log: [ "Multi line", "Multiline" ]
+ +

 

+ +

امثلة

+ +

تبين الامثلة التالية بعض استخدامات الريجكس

+ +

اعادة صياغة المدخلات النصية.

+ +

يوضح المثال التالي كيف يمكن للريجكس ان يتلاعب في بنية السلسلة النصية، وايضا كيفية استخدام ()string.split و ()string.replace. سيقوم السكريبت التالي بتنظيف واعادة صياغة السلسلة النصية، التي تحتوي على اسماء مفصولة بمسافات فارغة، تابات، وبالظبط فاصلة منقوطة واحدة. واخيرا سيقوم بعكس هذه الاسماء وترتيبها من a الى z.

+ +
// The name string contains multiple spaces and tabs,
+// and may have multiple spaces between first and last names.
+var names = 'Orange Trump ;Fred Barney; Helen Rigby ; Bill Abel ; Chris Hand ';
+
+var output = ['---------- Original String\n', names + '\n'];
+
+// Prepare two regular expression patterns and array storage.
+// Split the string into array elements.
+
+// pattern: possible white space then semicolon then possible white space
+var pattern = /\s*;\s*/;
+
+// Break the string into pieces separated by the pattern above and
+// store the pieces in an array called nameList
+var nameList = names.split(pattern);
+
+// new pattern: one or more characters then spaces then characters.
+// Use parentheses to "memorize" portions of the pattern.
+// The memorized portions are referred to later.
+pattern = /(\w+)\s+(\w+)/;
+
+// Below is the new array for holding names being processed.
+var bySurnameList = [];
+
+// Display the name array and populate the new array
+// with comma-separated names, last first.
+//
+// The replace method removes anything matching the pattern
+// and replaces it with the memorized string—the second memorized portion
+// followed by a comma, a space and the first memorized portion.
+//
+// The variables $1 and $2 refer to the portions
+// memorized while matching the pattern.
+
+output.push('---------- After Split by Regular Expression');
+
+var i, len;
+for (i = 0, len = nameList.length; i < len; i++) {
+  output.push(nameList[i]);
+  bySurnameList[i] = nameList[i].replace(pattern, '$2, $1');
+}
+
+// Display the new array.
+output.push('---------- Names Reversed');
+for (i = 0, len = bySurnameList.length; i < len; i++) {
+  output.push(bySurnameList[i]);
+}
+
+// Sort by last name, then display the sorted array.
+bySurnameList.sort();
+output.push('---------- Sorted');
+for (i = 0, len = bySurnameList.length; i < len; i++) {
+  output.push(bySurnameList[i]);
+}
+
+output.push('---------- End');
+
+console.log(output.join('\n'));
+ +

استخدام الرموز الخاصة للتحقق من صحة المدخلات.

+ +

في المثال التالي، يتوقع من المستخدم ادخال رقم الهاتف. عندما سينقر المستخدم على زر "الفحص" سيقوم السكريبت بفحص صحة الرقم. اذا كان الرقم صحيحا، سيقوم السكريبت باظهار رسالة تشكر المستخدم وتظهر الرقم المدخل. اذا كان الرقم غير صحيح، سيقوم السكريبت باخبار المستخدم بان الرقم المدخل غير صحيح.

+ +

بعد non-capturing parentheses (?: سينظر الريجكس الى الثلاثة ارقام \d{3} او | الى القوس اليساري \( متبوعا بثلاثة ارقام \d{3} متبوعة بقوس الاغلاق \), (نهاية non-capturing parenthesis ))، متبوعة بشرطة واحدة تليها الباكسلاش او النقطة الكسرية، اذا وجدت قم بفهرستها ([-\/\.])، متبوعة بثلاث ارقام \d{3}، متبوعة باستدعاء الجزء المفهرس \1, متبوعا باربعة ارقام \d{4}.

+ +

يتم تنشيط حدث التغيير عندما يقوم المستخدم بالضغط على إنتر وملأ القيمة RegExp.input.

+ +
<!DOCTYPE html>
+<html>
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+    <meta http-equiv="Content-Script-Type" content="text/javascript">
+    <script type="text/javascript">
+      var re = /(?:\d{3}|\(\d{3}\))([-\/\.])\d{3}\1\d{4}/;
+      function testInfo(phoneInput) {
+        var OK = re.exec(phoneInput.value);
+        if (!OK)
+          window.alert(phoneInput.value + ' isn\'t a phone number with area code!');
+        else
+          window.alert('Thanks, your phone number is ' + OK[0]);
+      }
+    </script>
+  </head>
+  <body>
+    <p>Enter your phone number (with area code) and then click "Check".
+        <br>The expected format is like ###-###-####.</p>
+    <form action="#">
+      <input id="phone"><button onclick="testInfo(document.getElementById('phone'));">Check</button>
+    </form>
+  </body>
+</html>
+
+ +

{{PreviousNext("Web/JavaScript/Guide/Text_formatting", "Web/JavaScript/Guide/Indexed_collections")}}

diff --git a/files/ar/web/javascript/guide/working_with_objects/index.html b/files/ar/web/javascript/guide/working_with_objects/index.html new file mode 100644 index 0000000000..83f3390467 --- /dev/null +++ b/files/ar/web/javascript/guide/working_with_objects/index.html @@ -0,0 +1,516 @@ +--- +title: العمل مع الكائنات +slug: Web/JavaScript/Guide/Working_with_Objects +translation_of: Web/JavaScript/Guide/Working_with_Objects +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Regular_Expressions", "Web/JavaScript/Guide/Details_of_the_Object_Model")}}
+ +

تم تصميم جافا سكريبت على نموذج بسيط يستند إلى الكائنات. الكائن هو عبارة عن مجموعة من الخصائص، كل خاصية لها اسم وقيمة key/value يمكن أن تكون قيمة هذه الخاصية عبارة عن دالة، وفي هذه الحالة يمكن ان تسمى بالوظيفة « method ». بالإضافة إلى الكائنات الأصلية التي توفرها بيئة المتصفحات، يمكنك انشاء كائنات خاصة بك. يصف هذا الفصل كيفية استخدام الكائنات، والخصائص والدوال او الوظائف، وايضا كيفية إنشاء الكائنات الخاصة بك.

+ +

نظرة عامة حول الكائنات

+ +
+

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

+ +

في الجافاسكريبت، الكائن هو كيان مستقل بخصائصه وانواعه، يمكن مقارنته بكوب، على سبيل المثال.الكوب هو كائن له خصائصه، الكوب له لون، له شكل، له وزن، صنع بمواد معينة، واشياء اخرى. بنفس الطريقة، كائنات الجافا سكريبت لها ايضا خصائصها التي تميزها.

+ +

الكائنات والخصائص

+ +

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

+ +
objectName.propertyName
+
+ +

ككل متغيرات جافاسكريبت،  اسم الكائن واسم الخاصية حساسة تجاه الاحرف (case sensitive). يمكنك تعيين خاصية ومنحها قيمة اولية. على سبيل المثال، لنقم بانشاء كائن باسم myCar وتعين خصائص له بالاسماء التالية : make, model و year كما في المثال التالي :

+ +
var myCar = new Object();
+myCar.make = 'Ford';
+myCar.model = 'Mustang';
+myCar.year = 1969;
+
+ +

خصائص الكائن الغير معرفة هي {{jsxref("undefined")}} (وليست {{jsxref("null")}}).

+ +
myCar.color; // undefined
+ +

يمكن الوصول الى خصائص الكائنات عن طريق الاقواس المربعة بدلا من نقطة التدوين، في بعض الاحيان يكون من الضروري استخدام الاقواس المربعة للوصول الى خصائص الكائن (لمزيد من المعلومات شاهد property accessors).  في بعض الاحيان تسمى الكائننات بمصفوفات مترابطة (associative arrays)، نظرا للشبه الكبير بينهما، حيث يمكن استخدام اسم الخاصية للوصول إلى قيمتها، الامر الذي تعتمده ايضا المصفوفات الترابطية. على سبيل المثال  يمكن الوصول إلى خصائص الكائن myCar على النحو التالي:

+ +
myCar['make'] = 'Ford';
+myCar['model'] = 'Mustang';
+myCar['year'] = 1969;
+
+ +

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

+ +
// four variables are created and assigned in a single go,
+// separated by commas
+var myObj = new Object(),
+    str = 'myString',
+    rand = Math.random(),
+    obj = new Object();
+
+myObj.type              = 'Dot syntax';
+myObj['date created']   = 'String with space';
+myObj[str]              = 'String value';
+myObj[rand]             = 'Random Number';
+myObj[obj]              = 'Object';
+myObj['']               = 'Even an empty string';
+
+console.log(myObj);
+
+ +

يرجى ملاحظة أن كافة المفاتيح في الاقواس المربعة تم تحويلها إلى سلسلة نصية (string type)، لان الكائنات في جافاسكريبت تتطلب بان يكون نوع المفتاح سلسلة نصية فقط، على سبيل المثال، في المثال اعلاه، عندما تم اضافة المفتاح rand الى ال myObj، الجافاسكريبت استدعت الوظيفة ()obj.toString بشكل اوتوماتيكي، واستخدمت ناتج السلسلة النصية كمفتاح جديد.  
+ مع العلم ان ("typeof rand === "number ).

+ +

يمكنك أيضا الوصول إلى الخصائص باستخدام قيمة نصية تم تخزينها في متغير :

+ +
var propertyName = 'make';
+myCar[propertyName] = 'Ford';
+
+propertyName = 'model';
+myCar[propertyName] = 'Mustang';
+
+ +

يمكنك استخدام for...in لعمل تكرار على خصائص الكائن القابلة للتصفح ( لمزيد من المعلومات حول enumerable properties ). لتوضيح ما نعنيه : تقوم الدالة التالية باظهار خصائص الكائن، عندما سيمرر لها الكائن واسم الكائن كبارامترات :

+ +
function showProps(obj, objName) {
+  var result = '';
+  for (var i in obj) {
+    // obj.hasOwnProperty() is used to filter out properties from the object's prototype chain
+    if (obj.hasOwnProperty(i)) {
+      result += objName + '.' + i + ' = ' + obj[i] + '\n';
+    }
+  }
+  return result;
+}
+
+ +

وهكذا، باستدعاء الدالة على هذا النحو showProps(myCar, "myCar") سينتج عنها النتائج التالية :

+ +
myCar.make = Ford
+myCar.model = Mustang
+myCar.year = 1969
+ +

تصفح خصائص الكائن

+ +

ابتداءا من ECMAScript 5، هناك ثلاثة طرق لتصفح/المرور على خصائص الكائن :

+ + + +

قبل ECMAScript 5، لم يكن هناك أية طريقة لتصفح كافة خصائص الكائن. الا انه، يمكن تحقيق ذلك باستخدام الدالة التالية:

+ +
function listAllProperties(o) {
+	var objectToInspect;
+	var result = [];
+
+	for(objectToInspect = o; objectToInspect !== null; objectToInspect = Object.getPrototypeOf(objectToInspect)) {
+      result = result.concat(Object.getOwnPropertyNames(objectToInspect));
+	}
+
+	return result;
+}
+
+ +

يمكن لهذه  الدالةان تكون مفيدة في الكشف عن الخصائص "المخفية" (الخصائص الموجودة في ال prototype chain والتي لا يمكن الوصول إليها من خلال الكائن، بسبب وجود خاصية اخرى لها نفس الاسم في ال prototype chain. لجدولة الخصائص الظاهرة فقط، عليك إزالة التكرار في المصفوفة.

+ +

إنشاء كائنات جديدة

+ +

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

+ +

كما يمكنك ايضا انشاء كائن بواسطة منشئ الوظيفة ( constructor function ) ومن ثم انشاء مثيل/نسخة له، من خلال الكلمة المحجوزة new.

+ +

استخدام object initializers

+ +

بالإضافة إلى إنشاء كائنات باستخدام constructor function، يمكنك إنشاء كائنات باستخدام مهيئ الكائن. هذا النوع من الكائنات  يشار إليه في بعض الأحيان ب object literal notation . وهو يتسق مع المصطلحات المستخدمة من قبل ++C.

+ +

التعبير عن كائن باستخدام object initializers:

+ +
var obj = { property_1:   value_1,   // property_# may be an identifier...
+            2:            value_2,   // or a number...
+            // ...,
+            'property n': value_n }; // or a string
+
+ +

حيث ان obj هو اسم الكائن الجديد، وكل property_i هو معرف الخاصية، يمكن ان يكون (اما اسما أو رقما أو سلسلة نصية)،في حين ان كل value_i هي تعليمة برمجية سيتم تعيينها كقيمه إلى الخاصية property_i يمكن (تعينها مباشرة او عن طريق اسنادها الى متغير خارجي).

+ +

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

+ +
var value_1 = 600,
+value_2 = 400;
+({
+    property_1: value_1,
+    2: value_2,
+    "property n": "Measurement",
+    init: function(){
+        console.log( this["property n"] +": "+ this.property_1 + "x" + this[2]);
+    }
+}).init(); // Measurement: 600x400
+
+
+ +

مهيئات الكائن، هي تعليمات برمجية، وكل مهئ سيخلق كائن جديد في التعليمة البرمجية التي سيتم تنفيذها. مهيآت الكائنات المتطابقة تنشئ كائنات مميزة والتي لا يمكن مقارنتها ببعضها البعض. يتم إنشاء الكائنات بنفس طريقة انشاء كائن جديد ()new Object، الكائنات المنشاة من خلال ال object literal هي مثيلات الكائن Object.

+ +

تقوم التعليمة البرمجية التالية، بانشاء كائن وتعيينه للمتغير x في حالة ما اذا كان الشرط صحيح:

+ +
if (cond) var x = {greeting: 'hi there'};
+
+ +

ينشئ المثال التالي، الكائن myHonda مع ثلاث خصائص. لاحظ أن الخاصية engine هي أيضا كائن له خصائصه.

+ +
var myHonda = {color: 'red', wheels: 4, engine: {cylinders: 4, size: 2.2}};
+
+ +

يمكنك أيضا استخدام مهيئات الكائن لإنشاء المصفوفات. شاهد array literals.

+ +

استخدام ال constructor function

+ +

كبديل، يمكنك إنشاء كائن مع هاتين الخطوتين:

+ +
    +
  1. تعريف نوع الكائن بانشاء constructor function. هناك عرف متفق عليه، وهو كتابة الحرف الاول من اسم الكائن بحروف كبيرة Capital.  بهدف تمييزه عن باقي الاسماء.
  2. +
  3. انشاء مثيل/نسخة للكائن بواسطة الكلمة المحجوزة new.
  4. +
+ +

لتحديد نوع الكائن، سنقوم بإنشاء دالة لتحديد اسم لهذا الكائن وخصائصه، ووظائفه، على سبيل المثال، فرضا انك تريد انشاء كائن للسيارات. سيتوجب عليك تسميته ب Car، وايضا يجب ان يمتلك خصائص مثل  make، model, و year.   للقيام بذلك، سيتوجب عليك انشاء الدالة التالية:

+ +
function Car(make, model, year) {
+  this.make = make;
+  this.model = model;
+  this.year = year;
+}
+
+ +

لاحظ اننا استخدمنا this لتعيين قيم لخصائص الكائن استناداً إلى القيم التي سيتم تمريرها إلى بارامترات الدالة.

+ +

الآن يمكنك إنشاء كائن باسم mycar على النحو التالي:

+ +
var mycar = new Car('Eagle', 'Talon TSi', 1993);
+
+ +

تقوم هذه التعليمة البرمجية بانشاء mycar، واسناد القيم المحددة لخصائصه. وبالتالي قيمة  mycar.make هي قيمة نصية "Eagle"، و mycar.year قيمة رقمية 1993، وهلم جرا.

+ +

يمكنك إنشاء اي عدد من الكائنات من النوع Car واستدعاؤها عن طريق الكلمة المحجوزة new. مثال:

+ +
var kenscar = new Car('Nissan', '300ZX', 1992);
+var vpgscar = new Car('Mazda', 'Miata', 1990);
+
+ +

يمكن للكائن ان يحتوي على خاصية تكون هي نفسها كائن اخر، على سبيل المثال، فرضا انك تريد انشاء كائن تحت الاسم person كما يلي:

+ +
function Person(name, age, sex) {
+  this.name = name;
+  this.age = age;
+  this.sex = sex;
+}
+
+ +

ومن ثم إنشاء مثيلين/نسختين للكائن person كما يلي:

+ +
var rand = new Person('Rand McKinnon', 33, 'M');
+var ken = new Person('Ken Jones', 39, 'M');
+
+ +

ثم، يمكنك إعادة تعريف ال Car لتضمين الخاصية owner التي ستمتلك الكائن person كما يلي:

+ +
function Car(make, model, year, owner) {
+  this.make = make;
+  this.model = model;
+  this.year = year;
+  this.owner = owner;
+}
+
+ +

بعد ذلك يمكنك إنشاء مثيلات/نسخ للكائنات الجديدة، باستخدام ما يلي:

+ +
var car1 = new Car('Eagle', 'Talon TSi', 1993, rand);
+var car2 = new Car('Nissan', '300ZX', 1992, ken);
+
+ +

لاحظ أنه بدلاً من تمرير سلسلة نصية أو قيمة رقمية عند إنشاء الكائنات الجديدة، في البيانات الواردة أعلاه تم تمرير الكائنان rand و ken كبرامترات خاصة بال owner. إذا كنت ترغب في معرفة الاسم الخاص ب car2، يمكنك الوصول إلى الخاصية بالطريقة التالية:

+ +
car2.owner.name
+
+ +

يمكنك  إضافة خاصية جديدة لكائن منشأ مسبقاً. على سبيل المثال، كما في التعليمة البرمجية التالية:

+ +
car1.color = 'black';
+
+ +

قمنا باضافة الخاصية color لل car1، وقمنا بتعيين القيمة "black." لها، ومع ذالك فهذا لن يجعلها متاحة لجميع الكائنات من النوع Car. لإضافة خاصية جديدة لكافة الكائنات من نفس النوع Car، يتوجب عليك اضافة هذه الخاصية لل constructor. الخاص بالكائن Car.

+ +

استخدام الوظيفة Object.create

+ +

يمكن أيضا إنشاء كائنات باستخدام الوظيفة {{jsxref("()Object.create")}} هذه الوظيفة يمكن أن تكون مفيدة للغاية، لأنها تتيح لك أن تختار ال prototype object للكائن الذي تريد إنشاء، دون الحاجة إلى تعريف ال constructor function (بواسطة new).

+ +
// Animal properties and method encapsulation
+var Animal = {
+  type: 'Invertebrates', // Default value of properties
+  displayType: function() {  // Method which will display type of Animal
+    console.log(this.type);
+  }
+};
+
+// Create new animal type called animal1
+var animal1 = Object.create(Animal);
+animal1.displayType(); // Output:Invertebrates
+
+// Create new animal type called Fishes
+var fish = Object.create(Animal);
+fish.type = 'Fishes';
+fish.displayType(); // Output:Fishes
+ +

الوراثة

+ +

في جافا سكريبت جميع الكائنات ترث من كائن واحد على الأقل. الكائن الذي ترث منه يسمى prototype، والخصائص الموروثة يمكن العثور عليها في ال prototype object لل constructor. شاهد Inheritance and the prototype chain  لمزيد من المعلومات.

+ +

فهرسة خصائص الكائن

+ +

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

+ +

ينطبق هذا الشرط عند إنشاء الكائن وخصائصه داخل ال constructor (كما فعلنا سابقا مع  الكائن من النوع Car) وكذالك عند تحديد خصائص فردية بشكل واضح (على سبيل المثال، "myCar.color = "red). اذا قمت في البداية بتعريف خاصية بمؤشرها الترتيبي، مثل "myCar[5] = "25 mpg، وتريد بعد ذالك الوصول اليها سيتوجب عليك استخدام المؤشر الترتيبي على هذا النحو  myCar[5].

+ +

والاستثناء لهذه القاعدة هي كائنات ال HTML، مثل forms array. يمكنك الاشارة دائما إلى الكائنات في هذه المصفوفات إما عن طريق مؤشرهم الترتيبي (حسب وجودها في الوثيقة) او عن طريق اسمائها (إذا كانت معرفة). فمثلا، اذا كان الوسم الثاني <FORM> في الوثيقة له السمة (attribute ) باسم "myForm"، يمكنك الاشارة الى هذا الفورم ب document.forms[1] او ب document.forms["myForm"] او ب document.forms.myForm.

+ +

التحكم في خصائص الكائن

+ +

يمكنك إضافة خاصية إلى كائن محدد سابقا باستخدام الخاصية prototype. هذا النمط سيجعل هذه الخاصية متاحة لكافة الكائنات من النوع المحدد، بدلاً من تحديدها لمثيل واحد فقط. التعليمة البرمجية التالية تضيف الخاصية color الى جميع الكائنات من نوع Car، وبعد ذالك تقوم بتعيين القيمة الجديدة للخاصية color الخاصة بالكائن car1.

+ +
Car.prototype.color = null;
+car1.color = 'black';
+
+ +

شاهد  prototype property  لل Function object وايضا JavaScript reference لمزيد من المعلومات.

+ +

تعريف الوظائف

+ +

الوظيفة هي دالة مرتبطة مع الكائن، أو، ببساطة،  هي خاصية في الكائن قيمتها دالة، يتم تعريف الوظيفة بنفس الطريقة التي يتم بها تعريف الدالة العادية، باستثناء ان هذه الاخيرة يجب أن يتم تعيينها كخاصية لكائن. شاهد ايضا method definitions لمزيد من المعلومات، وكمثال على ما تم ذكره:

+ +
objectName.methodname = function_name;
+
+var myObj = {
+  myMethod: function(params) {
+    // ...do something
+  }
+
+  // OR THIS WORKS TOO
+
+  myOtherMethod(params) {
+    // ...do something else
+  }
+};
+
+ +

حيث ان ال objectName كائن موجود، وال methodname هو الاسم المعين إلى الوظيفة، و function_name هو اسم الدالة.

+ +

ثم يمكنك استدعاء الوظيفة في سياق الكائن كما يلي:

+ +
object.methodname(params);
+
+ +

يمكنك تعريف وظائف الكائن باستدعاء وظيفة معرفة في constructor الكائن. على سبيل المثال، يمكنك القيام بتعريف الدالة التي من شأنها تهيئة وعرض خصائص الكائن Car المعرف مسبقا، على سبيل المثال:

+ +
function displayCar() {
+  var result = 'A Beautiful ' + this.year + ' ' + this.make
+    + ' ' + this.model;
+  pretty_print(result);
+}
+
+ +

يمكنك استخدام الدالة pretty_print لاظهار الناتج على شكل نص افقي، تذكر ايضا على ان الكلمة المحجوزة this ستشير الى السياق الذي تنتمي اليه الدالة نفسها وفي هذه الحالة هو ال constructur Car

+ +

 يمكننا بعد ذالك تعيين هذه الدالة كوظيفة في ال constructeur Car على النحو التالي:

+ +
this.displayCar = displayCar;
+
+ +

التعليمة البرمجية النهائية:

+ +
function Car(make, model, year, owner) {
+  this.make = make;
+  this.model = model;
+  this.year = year;
+  this.owner = owner;
+  this.displayCar = displayCar;
+}
+
+ +

الان يمكنك استدعاء الوظيفة displayCar لكلا الكائنين على النحو التالي:

+ +
car1.displayCar();
+car2.displayCar();
+
+ +

استخدام this كمرجع للكائنات

+ +

جافاسكريبت لديها الكلمة المحجوزة لها this، يمكنك استخدامها مع الوظائف للرجوع/الاشارة إلى الكائن الحالي. على سبيل المثال، لنفترض ان لديك دالة تسمى validate تقوم بالتحقق من صحة المدخلات:

+ +
function validate(obj, lowval, hival) {
+  if ((obj.value < lowval) || (obj.value > hival)) {
+    alert('Invalid Value!');
+  }
+}
+
+ +

يمكن استدعاء هذه الدالة  عن طريق معالج الحدث onchange، وستشير الكلمة المحجوزة this الى العنصر المتواجدة به (تنفيذ الدالة على هذا العنصر). كما في المثال التالي:

+ +
<input type="text" name="age" size="3"
+  onChange="validate(this, 18, 99)">
+
+ +

بشكل عام this تشير الى الكائن الذي يطلب الوظيفة.

+ +

يمكن ايضا استخدام this مع معالج الحدث بشكل مباشر، كما في المثال التالي:

+ +
<form name="myForm">
+<p><label>Form name:<input type="text" name="text1" value="Beluga"></label>
+<p><input name="button1" type="button" value="Show Form Name"
+     onclick="this.form.text1.value = this.form.name">
+</p>
+</form>
+ +

Defining getters and setters

+ +

 getter هي الوظيفة التي تقوم بجلب قيمة خاصية معينة. setter هي الوظيفة التي تقوم بتعيين قيمة لخاصية معينة. يمكنك تعيينها سواء للكائنات الاساسية المعرفة مسبقا أو الى الكائنات المعرف من قبل المستخدم والتي تدعم إضافة خصائص جديدة. وتستخدم مع ال object literal.

+ +

يبين المثال التالي كيفية انشاء getters و setters من طرف المستخدم :

+ +
var o = {
+  a: 7,
+  get b() {
+    return this.a + 1;
+  },
+  set c(x) {
+    this.a = x / 2;
+  }
+};
+
+console.log(o.a); // 7
+console.log(o.b); // 8
+o.c = 50;
+console.log(o.a); // 25
+
+ +

خصائص الكائن هي :

+ + + +

يمكنك استخدام  getters و setters مع الوظائف المنشاة مسبقا، لتحقيق ذالك يمكننا استخدام الوظيفة Object.defineProperty او الوظيفة القديمة Object.prototype.__defineGetter__

+ +

يبين الكود التالي كيف ان  getters و setters بامكانها ان ترث ال  {{jsxref("Date")}} prototype لاضافة الخاصية year الى جميع ال instances الخاص بالكائن Date المنشا مسبقا، ولهذا سنقوم باستخدام بعض الوظائف الخاصة ب Date ك getFullYear و setFullYear :

+ +
var d = Date.prototype;
+Object.defineProperty(d, 'year', {
+  get: function() { return this.getFullYear(); },
+  set: function(y) { this.setFullYear(y); }
+});
+
+ +

تبين التعليمة البرمجية التالية كيفية استخدام الخاصية year الجديدة التي تم انشاؤها عن طريق getters و setters:

+ +
var now = new Date();
+console.log(now.year); // 2000
+now.year = 2001; // 987617605170
+console.log(now);
+// Wed Apr 18 11:13:25 GMT-0700 (Pacific Daylight Time) 2001
+
+ +

بصفة عامة،  getters و setters يمكن ان تكون:

+ + + +

عندما سنقوم بانشاء getters و setters باستخدام ال استخدام object initializers كل ما عليك القيام به هو البذء بانشاء الوظيفة getter اولا ومن تم تعريفها ب get وتليها الوظيفة setter وتعريفها ب set، وبالطبع، الوظيفة getter لا تحتاج الى اي باراميتر، فيما ستحتاج الوظيفة setter لبراميتر واحد وهو القيمة الجديدة ل set. فعلى سبيل المثال:

+ +
var o = {
+  a: 7,
+  get b() { return this.a + 1; },
+  set c(x) { this.a = x / 2; }
+};
+
+ +

getters او setters. يمكن أيضا أن تضاف إلى كائن ما في أي وقت بعد انشائه باستخدام الوظيفة Object.defineProperties، البراميتر الأول لهذه الوظيفة هو الكائن الذي تريد انشاء ال getter او setter له. البراميتر الثاني عبارة عن كائن يمثل الخصائص التي ستضاف الى الكائن الهدف ويتكون من مفتاح الخاصية، وهو اسم ال  getter او ال setter، وقيمة الخاصية، وهي عبارة عن كائن لتعريف وظائف ال  getter او ال setter. لدينا هنا نفس المثال السابق يبين بجلاء ما تحدثنا عنه:

+ +
var o = { a: 0 };
+
+Object.defineProperties(o, {
+    'b': { get: function() { return this.a + 1; } },
+    'c': { set: function(x) { this.a = x / 2; } }
+});
+
+o.c = 10; // Runs the setter, which assigns 10 / 2 (5) to the 'a' property
+console.log(o.b); // Runs the getter, which yields a + 1 or 6
+
+ +

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

+ +

حذف الخصائص

+ +

يمكنك حذف الخصائص الغير موروثة باستخدام الكلمة المحجوزة delete التعليمة البرمجية التالية توضح كيف يتم ذالك:

+ +
// Creates a new object, myobj, with two properties, a and b.
+var myobj = new Object;
+myobj.a = 5;
+myobj.b = 12;
+
+// Removes the a property, leaving myobj with only the b property.
+delete myobj.a;
+console.log ('a' in myobj); // yields "false"
+
+ +

يمكنك ايضا استخدام delete لحذف متغير عام، شرط ان لا يكون هذا المتغير معرف بواسطة الكلمة المحجوزة var.

+ +
g = 17;
+delete g;
+
+ +

مقارنة الكائنات

+ +

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

+ +
// Two variables, two distinct objects with the same properties
+var fruit = {name: 'apple'};
+var fruitbear = {name: 'apple'};
+
+fruit == fruitbear; // return false
+fruit === fruitbear; // return false
+ +
// Two variables, a single object
+var fruit = {name: 'apple'};
+var fruitbear = fruit;  // assign fruit object reference to fruitbear
+
+// here fruit and fruitbear are pointing to same object
+fruit == fruitbear; // return true
+fruit === fruitbear; // return true
+
+ +
fruit.name = 'grape';
+console.log(fruitbear);    // yields { name: "grape" } instead of { name: "apple" }
+
+ +

لمزيد من المعلومات حول عوامل المقارنة، شاهد Comparison operators.

+
+ +

See also

+ + + +

{{PreviousNext("Web/JavaScript/Guide/Regular_Expressions", "Web/JavaScript/Guide/Details_of_the_Object_Model")}}

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" new file mode 100644 index 0000000000..af934b397d --- /dev/null +++ "b/files/ar/web/javascript/guide/\330\247\331\204\330\257\331\210\330\247\331\204/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")}}

-- cgit v1.2.3-54-g00ecf