اذهب إلى المحتوى

الحلقات في جافا سكريبت


ابراهيم الخضور

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

  1. أساسيات علوم الحاسب
  2. أساسيات HTML
  3. أساسيات عمل CSS
  4. أساسيات لغة جافا سكريبت

ما هي فائدة الحلقات؟

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

مثال عن شيفرة تستخدم الحلقات

لنفرض أنك تريد رسم 100 دائرة عشوائية ضمن العنصر <canvas> انقر الزر "Update" لتنفيذ الشيفرة مرة تلو اﻷخرى لترى مجموعات مختلفة من الدوائر):

إليك شيفرة جافا سكريبت التي تنفّذ المطلوب:

const btn = document.querySelector("button");
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");

document.addEventListener("DOMContentLoaded", () => {
  canvas.width = document.documentElement.clientWidth;
  canvas.height = document.documentElement.clientHeight;
});

function random(number) {
  return Math.floor(Math.random() * number);
}

function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  for (let i = 0; i < 100; i++) {
    ctx.beginPath();
    ctx.fillStyle = "rgba(255,0,0,0.5)";
    ctx.arc(
      random(canvas.width),
      random(canvas.height),
      random(50),
      0,
      2 * Math.PI,
    );
    ctx.fill();
  }
}

btn.addEventListener("click", draw);

مع أو بدون حلقة

ليس عليك فهم الشيفرة بأكملها اﻵن، لكن ألق نظرة على الجزء الذي يرسم 100 دائرة في الشيفرة:

for (let i = 0; i < 100; i++) {
  ctx.beginPath();
  ctx.fillStyle = "rgba(255,0,0,0.5)";
  ctx.arc(
    random(canvas.width),
    random(canvas.height),
    random(50),
    0,
    2 * Math.PI,
  );
  ctx.fill();
}
  • تُعيد الدالة random المعرّفة سابقًا رقمًا صحيحًا محصورًا بين الصفر و 1-x. أما الفكرة العامة فهي أننا نستخدم حلقة لتكرار الشيفرة السابقة 100 مرة، وكل مرة ترسم الشيفرة دائرة في مكان عشوائي من الصفحة. وتبقى كمية الشيفرة اللازمة لرسم الدائرة نفسها سواءً رسمنا 10 أو 100 أو 1000 دائرة، وما يتغير فقط هو عدد مرات التكرار، ولو لم نستخدم الحلقة كان لا بد من كتابة الشيفرة التالية في كل مرة نريد رسم دائرة:
ctx.beginPath();
ctx.fillStyle = "rgba(255,0,0,0.5)";
ctx.arc(
  random(canvas.width),
  random(canvas.height),
  random(50),
  0,
  2 * Math.PI,
);
ctx.fill();

وسيكون الأمر مملًا وصعب التنقيح والصيانة.

استخدام الحلقات للتنقل ضمن مجموعات

غالبًا ما تستخدم الحلقة للتنقل بين مجموعة من العناصر لتنفيذ أمر ما على كل عنصر. ومن اﻷمثلة على المجموعات نجد المصفوفات، إضافة إلى بُنى أخرى في جافا سكريبت مثل المجموعات Sets و الخرائط Maps.

الحلقة for...of

تعد هذه الحلقة أساسية في النقل ضمن عناصر مجموعة:

const cats = ["Leopard", "Serval", "Jaguar", "Tiger", "Caracal", "Lion"];

for (const cat of cats) {
  console.log(cat);
}

في مثالنا هذا، تنص العبارة البرمجية for (const cat of cats) على ما يلي:

  1. إذا كانت cats مجموعة من العناصر استخرج العنصر اﻷول منها.
  2. إسناد قيمة هذا العنصر إلى المتغير cat ومن ثم نفّذ الشيفرة الموجودة ضمن القوسين المعقوصين {}.
  3. استخراج العنصر التالي وكرر الخطوة 2 حتى تصل إلى نهاية المجموعة.

التابعين filter و map

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

function toUpper(string) {
  return string.toUpperCase();
}

const cats = ["Leopard", "Serval", "Jaguar", "Tiger", "Caracal", "Lion"];

const upperCats = cats.map(toUpper);

console.log(upperCats);
// [ "LEOPARD", "SERVAL", "JAGUAR", "TIGER", "CARACAL", "LION" ]

مررنا في مثالنا السابق دالة إلى التابع ()cats.map الذي يستدعيها مرة لكل عنصر من عناصر المصفوفة، ثم يمرر هذا العنصر إلى الدالة ويجمّع القيم العائدة عنها بعد كل استدعاء ضمن مصفوفة جديدة تحتوى عناصر المصفوفة القديمة بعد تغيير حالة أحرف هذه العناصر.

[ "LEOPARD", "SERVAL", "JAGUAR", "TIGER", "CARACAL", "LION" ]

أما الحلقة الثانية فيقدمها التابع ()filter الذي يختبر كل عنصر من عناصر المجموعة ويعيد مصفوفة جديدة تضم العناصر التي تحقق شرطًا معينًا:

function lCat(cat) {
  return cat.startsWith("L");
}

const cats = ["Leopard", "Serval", "Jaguar", "Tiger", "Caracal", "Lion"];

const filtered = cats.filter(lCat);

console.log(filtered);
// [ "Leopard", "Lion" ]

يبدو الأمر مشابهًا للتابع ()map، ما عدا أن القيمة التي تعيدها الدالة التي نمررها هي قيمة منطقية. فإذا كانت true يُضمّن العنصر في المصفوفة الجديدة وإلا لن يُضمَّن. أما وظيفة الدالة في هذا المثال فهي اختبار العناصر التي تبدأ بالحرف "L"، لذا ستكون النتيجة كالتالي:

[ "Leopard", "Lion" ]

ولاحظ كيف يُستخدم التابعان ()map و ()filter في بعض اﻷحيان مع دوال وهذا ما سندرسه لاحقًا. وباستخدام الدوال يمكن إعادة كتابة الشيفرة السابقة كالتالي:

const cats = ["Leopard", "Serval", "Jaguar", "Tiger", "Caracal", "Lion"];

const filtered = cats.filter((cat) => cat.startsWith("L"));
console.log(filtered);
// [ "Leopard", "Lion" ]

حلقة forالمعيارية

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

for (initializer; condition; final-expression) {
  // code to run
}

لدينا هنا:

  1. الكلمة المحجوزة for.
  2. ضمن القوسين التاليين ثلاثة عناصر تفصل بينها فاصلة:
    • مهييء initializer: وهو متغيّر له قيمة عددية محددة سوف تزداد لتعدد المرات التي تثنفَّذ فيها الحلقة. ويُشار إليها أحيانًا بالعداد.
    • شرط condition: ويحدد متى ستنتهي الحلقة. وهو عادة عبارة برمجية تستخدم عامل موازنة وتختبر إذا ما تحقق الشرط أم لا.
    • عبارة إنهاء final-expression:وتُنفّذ أو تُقيَّّم في كل مرة تنهي الحلقة أحد التكرارات. وتُستخدم عادة لتزيد (أو تنقص) العداد لتقربه من النقطة التي لا يتحقق بعدها الشرط (العنصر الثاني).
  3. أقواس معقوصة تضم كتلة من الشيفرة التي تُنفَّذ في كل تكرار للحلقة.

مثال عن حلقة for: حساب مربعات أعداد

لنلق نظرة على مثال حقيقي لنتصوّر اﻷمر بوضوح أكثر:

const results = document.querySelector("#results");

function calculate() {
  for (let i = 1; i < 10; i++) {
    const newResult = `${i} x ${i} = ${i * i}`;
    results.textContent += `${newResult}\n`;
  }
  results.textContent += "\nFinished!";
}

const calculateBtn = document.querySelector("#calculate");
const clearBtn = document.querySelector("#clear");

calculateBtn.addEventListener("click", calculate);
clearBtn.addEventListener("click", () => (results.textContent = ""));

تُعطي الشيفرة السابقة الخرج التالي:

تحسب الشيفرة السابقة مربعات الأعداد من 1 إلى 9 وتطبع النتيجة، وتُستخدم الحلقة for كأساس لإجراء الحسابات. لنحلل بشيء من التفصيل العبارة
for (let i = 1; i < 10; i++):

  1. المهيء (let i = 1) يبدأ العداد i من القيمة 1. ولاحظ ضرورة استخدام التعليمة let لأننا نعيد إسناد قيمة له عند كل تكرار.
  2. الشرط (i < 10) ويعني أن تستمر الحلقة في تكرار نفسها طالما أن i أصغر من 10.
  3. عبارة اﻹنهاء (++i) وتضيف واحد إلى العداد عند إتمام كل تكرار. نحسب داخل الحلقة مربع القيمة الحالية للمتغير i بالشكل :i*i، وننشئ عبارة نصية تضم العملية التي أجريناها ونتيجتها. كما نضيف السلسلة n\ إلى آخر السلسلة النصية كي تُطبع نتيجة التكرار التالي على سطر جديد. وما سيحدث اﻵن هو:
  4. خلال التكرار الأول ستكون i=1، وستكون النتيجة 1x1=1.
  5. خلال التكرار الثاني ستكون i=2، وستكون النتيجة 2x2=4.
  6. تستمر الحلقة بهذا الشكل.
  7. عندما تصبح i=10 تتوقف الحلقة عند تنفيذ الشيفرة ما داخل القوسين المعقوصين وتنتقل إلى الشفرة التي تلي الحلقة وتطبع الرسالة !finished على سطر جديد.

التنقل بين عناصر مجموعة باستخدام الحلقة for

بإمكانك استخدام الحلقة for للتنقل بين عناصر مجموعة بدلًا من for...of. لنعد إلى مثال for...of السابق:

const cats = ["Leopard", "Serval", "Jaguar", "Tiger", "Caracal", "Lion"];

for (const cat of cats) {
  console.log(cat);
}

سنكتب الشيفرة كالتالي:

const cats = ["Leopard", "Serval", "Jaguar", "Tiger", "Caracal", "Lion"];

for (let i = 0; i < cats.length; i++) {
  console.log(cats[i]);
}

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

  • أن تبدأ i من القيمة 1 وتنسى أن تعداد المصفوفات يبدأ من 0.
  • قد تنهي الحلقة عند i<=cats.length وتنسى أن نآخر دليل في المصفوفة هو length-1. لأسباب كهذه، يُفضّل استخدام for...of إن استطعت ذلك، لكنك ستحتاج في بعض اﻷحيان إلى for عند النقل بين عناصر مصفوفة. فإن أردت مثلًا طباعة رسالة تضم قائمة بأسماء القطط باستخدام الشيفرة التالية:
const cats = ["Pete", "Biggles", "Jasmine"];

let myFavoriteCats = "My cats are called ";

for (const cat of cats) {
  myFavoriteCats += `${cat}, `;
}

console.log(myFavoriteCats); // "My cats are called Pete, Biggles, Jasmine, "

لن تكون النتيجة (من ناحية تكوين الجملة في اﻹنكليزية) مصاغة بالكل الصحيح:

My cats are called Pete, Biggles, Jasmine,

لهذا يجب أن تتعامل الحلقة مع آخر اسم بشكل مختلف حتى تكون النتيجة بالشكل:

My cats are called Pete, Biggles, and Jasmine.

ولفعل ذلك، ينبغي أن نعرف دليل آخر عنصر ونحتاج عندها إلى الحلقة for لتفحّص قيمة i:

const cats = ["Pete", "Biggles", "Jasmine"];

let myFavoriteCats = "My cats are called ";

for (let i = 0; i < cats.length; i++) {
  if (i === cats.length - 1) {
    // We are at the end of the array
    myFavoriteCats += `and ${cats[i]}.`;
  } else {
    myFavoriteCats += `${cats[i]}, `;
  }
}

console.log(myFavoriteCats); // "My cats are called Pete, Biggles, and Jasmine."

الخروج من الحلقة باستخدام التعليمة break

إن أردت الخروج من حلقة باكرًا قبل انتهاء جميع التكرارات، استخدم التعليمة break التي رأيناها في مقال العبارات الشرطية عند التعامل مع البنية switch، إذ تنهي التعليمة break البنية switch في الحالة case التي تحقق تطابقًا مع الشرط. يتكرر اﻷمر ذاته مع الحلقات، إذ يمكن إنهاء الحلقة مباشرة باستخدام break وجعل المتصفح يقفز إلى الشيفرة التي تلي الحلقة. فلو أردنا مثلًا تطبيقًا للبحث عبر مصفوفة تضم جهات اتصال وأرقام هواتف ونريد فقط رقمًا محددًا، سنحتاج إلى شيفرة HTML تضم عنصر إدخال نصي <input> لإدخال الرقم الذي نبحث عنه وزر <button> لتنفيذ العملية وفقرة نصية <p> لعرض النتيجة:

<label for="search">Search by contact name: </label>
<input id="search" type="text" />
<button>Search</button>

<p></p>

ستكون شيفرة جافا سكريبت كالتالي:

const contacts = [
  "Chris:2232322",
  "Sarah:3453456",
  "Bill:7654322",
  "Mary:9998769",
  "Dianne:9384975",
];
const para = document.querySelector("p");
const input = document.querySelector("input");
const btn = document.querySelector("button");

btn.addEventListener("click", () => {
  const searchName = input.value.toLowerCase();
  input.value = "";
  input.focus();
  para.textContent = "";
  for (const contact of contacts) {
    const splitContact = contact.split(":");
    if (splitContact[0].toLowerCase() === searchName) {
      para.textContent = `${splitContact[0]}'s number is ${splitContact[1]}.`;
      break;
    }
  }
  if (para.textContent === "") {
    para.textContent = "Contact not found.";
  }
});

  1. نعرّف أولًا بعض المتغيّرات منها مصفوفة جهات الاتصال المؤلفة من عناصر نصيّة تحتوي على اسم ورقم هاتف تفصل بينهما نقطتان فوق بعضهما :

  2. نربط بعدها مترصّد أحداث إلى الزر btn لتشغيل الشيفرة التي تنفّذ البحث وتعيد النتيجة عند النقر عليه.

  3. نخزّن القيم المدخلة إلى مربع اﻹدخال في المتغيّر searchName قبل أن نفرّغه ونعيد إليه تركيز الدخل من جديد. ولاحظ استخدام التابع ()toLowerCase كي يحول النص المدخل إلى حروف صغيرة وبالتالي لن يكون البحث حساسًا لحالة الحروف.

  4. نأتي إلى الجزء الذي يضم الحلقة for...of:

  5. نفصل بداية جهة الاتصال عند النقطتين المتعامدتين ونخزّن القيمتين الناتجتين عن عملية الفصل في مصفوفة تُدعى .

  6. نستخدم بعد ذلك عبارة شرطية لاختبار إن كانت قيمة splitContact[0] (وتمثّل اسم المستخدم المحوّل إلى حروف صغيرة) متطابقة مع القيمة المخزّنة في المتغيرsearchName فإن وجد التطابق نعرض في الفقرة النصية الرقم الموافق ثم نستخدم break ﻹنهاء الحلقة.

  7. إن لم نجد جهة اتصال مطابقة للبحث لن تظهر أي قيمة في الفقرة النصية، لهذا نضع ضمنها النص "Contact not found." بمعني أننا لم نجد جهة الاتصال المطلوبة. ملاحظة: بإمكانك الاطلاع على الشيفرة المصدرية الكاملة لهذا المثال على جيت-هب، وتستطيع تجربته مباشرة كذلك.

تخطي أحد التكرارات باستخدام continue

تعمل التعليمة continue بشكل مشابه للتعليمة break لكنها تتخطى التكرار الحالي إلى التكرار التالي بدلًا من الخروج من الحلقة نهائيًا. لنلق نظرة على مثال آخر يأخذ عدة مدخلات ويعيد فقط اﻷعداد التي تمثل مرّبعات ﻷعداد صحيحة. إليك أولًا شيفرة HTML:

<label for="number">Enter number: </label>
<input id="number" type="number" />
<button>Generate integer squares</button>

<p>Output:</p>

وهذه شيفرة جافا سكريبت اللازمة:

const para = document.querySelector("p");
const input = document.querySelector("input");
const btn = document.querySelector("button");

btn.addEventListener("click", () => {
  para.textContent = "Output: ";
  const num = input.value;
  input.value = "";
  input.focus();
  for (let i = 1; i <= num; i++) {
    let sqRoot = Math.sqrt(i);
    if (Math.floor(sqRoot) !== sqRoot) {
      continue;
    }
    para.textContent += `${i} `;
  }
});

وهذا هو خرج البرنامج:

  1. يجب أن يكون الدخل في هذه الحالة عددًا (المتغير num)، وتبدأ الحلقة من 1 (لأن 0 لا يهمنا في هذا التطبيق). هنالك أيضًا شرط للخروج من الحلقة وهو أن يكون العداد أكبر من العدد المدخل num، ويزداد العداد بمقدار 1 في كل تكرار.
  2. نحسب الجذر التربيعي لكل عدد داخل الحلقة ياستخدام التابع (i)Math.sqrtومن ثم نتحقق أنه عدد صحيح بمقارنته مع نفسه عند تقريبه إلى أصغر عدد صحيح باستخدام التابع ()Math.floor.
  3. إن لم يتساوى الجذر التربيعي والقيمة المقرّبة له (==!) فهذا يعني أن الجذر التربيعي ليس عددًا صحيحًا ولن يكون مهمًا بالنسبة لنا لهذا نستخدم continue في هذه الحالة للانتقال إلى العدد التالي دون أن نسجّل هذا العدد.
  4. إن كان الجذر التربيعي صحيحًا نتخطى الكتلة if كليًا ولن تُنفَّذ التعليمة continue بل نضيف قيمة i وبعده مسافة فارغة إلى محتوى الفقرة النصية.

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

الحلقتين while و do...while

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

initializer
while (condition) {
  // code to run

  final-expression
}

تعمل الحلقة بشكل مشابه للحلقة for، إلا أن المهيّء يُضبط قبل الحلقة وعبارة الإنهاء موجودة ضمن الحلقة بعد الشيفرة التي تُنفَّذ عند تحقق الشرط بدلًا من وجودهما بين القوسين التاليين للتعليمة while إلى جانب عبارة الشرط. وكما نرى، فإن العناصر الثلاث السابقة الموجودة في حلقة for موجودة أيضًا في الحلقة while وبنفس الترتيب لأنك تحتاج إلى المهيئ قبل أن تختبر صحة الشرط ثم تُنفَّذ عبارة اﻹنهاء عند انتهاء تنفيذ شيفرة الحلقة التي تستمر طالما أن الشرط محقق.

نحاول تاليًا إعادة كتابة شيفرة مثالنا السابق عن القطط لكن باستخدام الحلقة while:

const cats = ["Pete", "Biggles", "Jasmine"];

let myFavoriteCats = "My cats are called ";

let i = 0;

while (i < cats.length) {
  if (i === cats.length - 1) {
    myFavoriteCats += `and ${cats[i]}.`;
  } else {
    myFavoriteCats += `${cats[i]}, `;
  }

  i++;
}

console.log(myFavoriteCats); // "My cats are called Pete, Biggles, and Jasmine."

وبالنسبة للحلقة do...while، فهي مشابهة جدًا للحلقة while مع بعض التغييرات في الصياغة:

initializer
do {
  // code to run

  final-expression
} while (condition)

نلاحظ في هذه الحالة أن المهيئ يأتي أولًا قبل بداية الحلقة ثم الكلمة المحجوزة do يتبعها قوسين معقوصين يضمان الشيفرة التي يجب تنفيذها ثم عبارة اﻹنهاء ثم يأتي بعد القوسين المعقوصين مباشرة التعليمة while يليها الشرط. إن الفرق الرئيسي بين الحلقتين السابقتين هو أن الشيفرة ضمن الحلقة do...while ستُنفَّذ على اﻷقل مرة واحدة قبل اختبار صحة الشرط. إي تُنفَّذ الشيفرة وبعدها يُختبر الشرط لتحديد الحاجة إلى تنفيذ الشيفرة مجددًا. أما في whileو forيُختبر الشرط أولًا. لنحاول تاليًا إعادة كتابة شيفرة مثالنا السابق عن القطط باستخدام الحلقة do...while:

const cats = ["Pete", "Biggles", "Jasmine"];

let myFavoriteCats = "My cats are called ";

let i = 0;

do {
  if (i === cats.length - 1) {
    myFavoriteCats += `and ${cats[i]}.`;
  } else {
    myFavoriteCats += `${cats[i]}, `;
  }

  i++;
} while (i < cats.length);

console.log(myFavoriteCats); // "My cats are called Pete, Biggles, and Jasmine."

تحذير: يجب التأكد في حلقات while و do...while وجميع الحلقات اﻷخرى من زيادة أو إنقاص المهيئ تبعًا للحالة حتى يصبح الشرط في مرحلة ما غير محقق وتنتهي الحلقة وإلا ستستمر الحلقة إلى ما لا نهاية أو سيوقفها المتصفح أو ستنهار الشيفرة. تُدعى هذه الحالة -حلقة لانهائية infinite loop-.

تطبيق عملي: إبدأ العد التنازلي!

نطلب إليك في هذا التمرين طباعة عد تنازلي من 10 إلى 0، ونريد تحديدًا:

  • حلقة من 10 إلى 0، وقد زوّدناك بالمهيئ ;let i = 10.
  • إنشاء فقرة نصية جديدة في كل تكرار للحلقة وإلحاقها بعنصر الخرج <div> الذي نختاره باستخدام اﻷمر :
  const output = document.querySelector('.output');

وقد زوّدناك في التعليقات بثلاث أسطر من الشيفرة يجب استخدامها ضمن الحلقة:

  • السطر;const para = document.createElement('p') الذي يُنشىء فقرة نصية جديدة.

  • السطر ;output.appendChild(para) الذي يُلحق الفقرة النصية بالعنصر <div>.

  • السطر =para.textContentالذي يجعل محتوى الفقرة ما تضعه من الناحية اليمنى للمساواة.

  • يتطلب كل تكرار نصًا مختلفًا يوضع ضمن الفقرة النصية وفقًا للعدد الذي وصلنا إليه، لذا تحتاج عبارة شرطية وعدة عبارات =para.textContent:

  • إن كان العدد هو 10 يجب طباعة "Countdown 10".

  • إن كان العدد هو 0 يجب طباعة "!Blast off".

  • يُطبع أي عدد آخر كما هو.

  • تذكّر أن تضيف عدادًا وانتبه إلى أننا نعد تنازليًا في تمريننا وليس تصاعديًا (لا تستخدم ++i!).

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

إن ارتكبت خطأً تستطيع أن تنقر على الزر "Reset" لتعود إلى الوضع الأساسي، كما يمكنك النقر على الزر "Show solution" لترى الحل.

تطبيق عملي: ملء قائمة المدعوين

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

  • كتابة حلقة تتنقل بين عناصر المصفوفة people.
  • تتحقق في كل مرور من أن اسم الشخص ليس "Phil"أو "Lola" مستخدمًا عبارة شرطية:
  • إن كان كذلك، ألحق الاسم بنهاية المحتوى النصي textContent للفقرة النصية refused يليه فاصلة وفراغ.
  • إن لم يكن كذلك، ألحق الاسم بنهاية المحتوى النصي textContent للفقرة النصية admitted يليه فاصلة وفراغ.

زوّدناك مسبقًا بأسطر الشيرة التالية:

  • السطر =+refused.textContent الذي يمثل بداية أمر ضم شيء ما إلى نهاية refused.textContent.
  • السطر =+admitted.textContent الذي يمثل بداية أمر ضم شيء ما إلى نهاية admitted.textContent.

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

إن ارتكبت خطأً تستطيع أن تنقر على الزر "Reset" لتعود إلى الوضع الأساسي، كما يمكنك النقر على الزر "Show solution" لترى الحل.

ما هو نوع الحلقة التي علي استخدامها؟

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

لنلق نظرة عليها جميعًا:

  1. الحلقة for...of:
for (const item of array) {
  // code to run
}
  1. الحلقةfor:
for (initializer; condition; final-expression) {
  // code to run
}
  1. الحلقة while:
initializer
while (condition) {
  // code to run

  final-expression
}
  1. الحلقة do...while:
initializer
do {
  // code to run

  final-expression
} while (condition)

ملاحظة: هناك حلقات أخرى لها ميزات مختلفة وفوائد في حالات محددة وخاصة لكننا لن نمر عليها في هذا المقال.

خلاصة

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

ترجمة -وبتصرف- لمقال Looping code

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...