حلقههای while و do while
گزارههای while برای اجرای تکراری دستورات کاربرد دارند.
یک گزارهی while دارای فرم کلی زیر است.
تا زمانی که condition دارای یک مقدار truthy باشد، دستورات
بدنهی حلقه اجرا میشوند. اگر بدنهی حلقه شامل فقط یک دستور باشد،
میتوانیم از آکلادها صرفنظر کنیم؛ البته این کار توصیه نمیشود.
loops.js
let i = 1;
while (i <= 5) {
console.log(i);
i++;
}
در اینجا وقتی برنامه به گزارهی while میرسد، متغیر i دارای مقدار 1 است.
پس، شرط حلقه برقرار است و بنابراین، دسورات بدنهی حلقه اجرا میشوند.
نتیجتاً مقدار 1 چاپ شده و یک واحد به i اضافه میشود. حالا i دارای مقدار 2 است و باز هم
شرط حلقه برقرار است و بنابراین، بدنهی حلقه یک بار دیگر اجرا میشود.
این روال ادامه دارد تا زمانی که در پنجمین تکرار، مقدار 5 چاپ شود و i به مقدار 6 برسد.
در این وضع، شرط حلقه دیگر برقرار نیست و بنابراین، برنامه از حلقه خارج میشود.
پس، خروجی این کد به صورت زیر خواهد بود.
1
2
3
4
5
while یک حلقهی pre-test است؛ یعنی شرط حلقه قبل از بدنهی حلقه قرار دارد.
بنابراین، این احتمال وجود دارد که دستورات بدنهی حلقه اصلاً اجرا نشوند.
اما یک ورژن post-test از این حلقه داریم که do while نام دارد.
سینتکس کلی یک گزارهی do while به صورت زیر است.
do {
} while (condition);
با توجه به اینکه در گزارههای do while، شرط حلقه بعد از بدنه قرار دارد،
دستورات بدنه لااقل یک بار اجرا میشوند. کد زیر باعث چاپ اعداد 1 تا 5 در خروجی میشود.
loops.js
let i = 1;
do {
console.log(i);
i++;
} while (i <= 5);
در مثالهای بالا، شرط حلقه یک عبارت بولین است اما امکان استفاده از عبارتهای
غیر بولین هم وجود دارد. دقت کنید که ما شرط اجرای دستورات بدنه را truthy بودن
عبارت عنوان کردیم. پس، اگر عبارت غیر بولینی به حلقه داده شود، به طور ضمنی به
بولین تبدیل میشود و اگر نتیجه true باشد، بدنهی حلقه اجرا میشود. مثال زیر را ببینید.
loops.js
let i = 5;
while (i) {
console.log(i);
i--;
}
نتیجهی اجرای این کد به صورت زیر خواهد بود.
5
4
3
2
1
حلقه for
حلقهی for کمی پیچیدهتر است اما بیشتر از سایر حلقهها مورد استفاده قرار میگیرد.
فرم کلی یک حلقهی for به صورت زیر است.
for (counter; condition; iterator) {
}
همانطور که میبینید، ابتدا کلمه کلیدی for و سپس یک جفت پرانتز ایجاد شده و درون پرانتزها
سه آیتم داریم که با
سمیکالن از هم جدا شدهاند. آیتم اول معمولاً متغیری است که روی یک مقدار عددی تنظیم شده و شمارندهی تعداد
دفعات اجرای حلقه محسوب میشود. به همین دلیل آن را counter نامیدهایم. آیتم دوم یعنی condition
یک عبارت شرطی
است که تعیین کنندهی زمان توقف حلقه است. در واقع، حلقه تا زمانی ادامه پیدا میکند که این شرط برقرار باشد.
آیتم سوم نیز iterator یا تکرارگر نامیده شده و با هر بار اجرای حلقه مقدار متغیر شمارنده را افزایش
یا کاهش میدهد تا بعد از هر بار اجرای حلقه یک گام به نقطهی پایان حلقه نزدیک شویم. در پایان نیز یک جفت آکلاد
قرار دارد که دستوراتی را که در هر تکرار حلقه باید انجام شوند، شامل است.
در مثال زیر از یک حلقهی for برای چاپ اعداد 1 تا 5 استفاده شده است.
loops.js
for (let i = 1; i <= 5; i++) {
console.log(i);
}
این فرم از حلقهی for که در اینجا دیدیم، فرم استاندارد این حلقه است.
در آینده با حلقههای for...in و for...of نیز آشنا خواهیم شد که اولی
برای پیمایش روی پراپرتیهای یک شیء و دومی برای پیمایش روی عناصر
آرایهها (و سایر اشیاء iterable) کاربرد دارند.
نقش break و continue
در حالت نرمال، یک حلقه زمانی به پایان میرسد که عبارت شرط حلقه به یک falsy تبدیل شود.
اما با استفاده از کلمه کلیدی break میتوانیم هر وقت که بخواهیم، حلقه را متوقف کنیم.
loops.js
for (let i = 0; i < 10; i++) {
if (i === 3) {
break;
}
console.log(i);
}
در این مثال، وقتی متغیر i به مقدار 3 برسد، دستور break اجرا شده و حلقه متوقف
میشود.
بنابراین، فقط اعداد 0، 1 و 2 در خروجی چاپ میشوند.
continiue را میتوانیم یک ورژن لایت از break بدانیم. چون break کل حلقه را متوقف میکند و
سراغ ادامهی دستورات برنامه میرود اما continue تکرار جاری را متوقف میکند و سراغ تکرار
بعدی میرود.
در مثال زیر، با استفاده از continue ترتیبی دادهایم که اعداد فرد یکرقمی چاپ شوند.
loops.js
for (let i = 0; i < 10; i++) {
if (i % 2 == 0) continue;
console.log(i);
}
برای مقادیر زوج متغیر i، دستور continue تکرار جاری را متوقف میکند و حلقه
را به تکرار بعدی میفرستد.
لیبل برای break/continue
وقتی در حلقههای تودرتو شده از break یا continue استفاده میکنیم،
داخلیترین حلقه ملاک عمل خواهد بود. برای روشن شدن این موضوع، مثال زیر را ببینید.
functions.js
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (i == 2) break;
console.log(`point (${i}, ${j})`);
}
console.log(i);
}
اگر کد بالا را بدون خطی که با * مشخص شده، اجرا کنیم، زوجهای
(0, 0) تا (2, 2) در خروجی چاپ میشوند. اما وجود این خط کد باعث میشود که وقتی i به مقدار 2 برسد،
حلقه متوقف شود. اما کدام حلقه؟ حلقهی داخلی یا بیرونی؟ برای دریافت جواب این سؤال، برنامه را اجرا میکنیم.
point (0, 0)
point (0, 1)
point (0, 2)
0
point (1, 0)
point (1, 1)
point (1, 2)
1
2
این خروجی نشان میدهد که دستور break روی حلقهی داخلی اعمال شده، نه بیرونی.
چون وقتی i به مقدار 2 رسیده، چاپ زوجها متوقف شده اما گزارهی console.log(i)
در حلقهی بیرونی
همچنان اجرا شده و مقدار 2 را در خط آخر چاپ کرده است.
اما اگر بخواهیم دستور break منجر به خروج از همهی حلقهها شود، باید
روی بیرونیترین حلقه اعمال شود. اینجاست که لیبلها به کمک ما میآیند.
میتوانیم روی حلقهها برچسب یا لیبل بزنیم و در واقع، نامی به آنها اختصاص دهیم.
سپس، هنگام استفاده از دستور break (یا continue) نام حلقهی مورد نظر
را مشخص کنیم.
functions.js
outer: for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (i == 2) break outer;
console.log(`point (${i}, ${j})`);
}
console.log(i);
}
در اینجا با استفاده از روشی که میبینید، روی حلقهی بیرونی لیبل زدهایم و سپس،
از این لیبل برای مشخص کردن حلقهی مورد اشارهی break استفاده کردهایم.
این کار باعث میشود که بیرونیترین حلقه متوقف شود و در نتیجه از کل
حلقهها خارج شویم. بنابراین، این بار خروجی به صورت زیر خواهد بود.
point (0, 0)
point (0, 1)
point (0, 2)
0
point (1, 0)
point (1, 1)
point (1, 2)
1