حلقهها و تکرار
حلقههای for، while و do while، دستورات break و continue، حلقههای تو در تو و مفاهیم Iterable و Iterator در جاوا اسکریپت
حلقه چیست؟
حلقه (Loop) ابزاری برای تکرار یک قطعه کد است. بهجای نوشتن چندین بار یک دستور، از حلقه استفاده میکنیم:
// بدون حلقه:
console.log(1);
console.log(2);
console.log(3);
// ... خستهکننده!
// با حلقه:
for (let i = 1; i <= 3; i++) {
console.log(i);
}
حلقه for
پرکاربردترین حلقه — سه بخش دارد: مقداردهی اولیه، شرط و افزایش:
// for (مقداردهی; شرط; گام)
for (let i = 0; i < 5; i++) {
console.log(i); // 0 1 2 3 4
}
// شمارش معکوس:
for (let i = 5; i > 0; i--) {
console.log(i); // 5 4 3 2 1
}
// گامهای سفارشی:
for (let i = 0; i <= 20; i += 5) {
console.log(i); // 0 5 10 15 20
}
حلقه while
تا زمانی که شرط برقرار باشد تکرار میکند. شرط قبل از اجرا بررسی میشود:
let count = 1;
while (count <= 3) {
console.log("شمارش:", count);
count++;
}
// شمارش: 1
// شمارش: 2
// شمارش: 3
// خطر: اگر شرط هرگز false نشود → حلقه بینهایت!
// let n = 0;
// while (n < 10) {
// console.log(n); // فراموش کردیم n را زیاد کنیم!
// }
حلقه do while
مثل while است اما شرط بعد از اجرا بررسی میشود — یعنی بلاک حداقل یک بار اجرا میشود:
let num = 10;
do {
console.log(num); // 10 (یک بار اجرا شد)
num++;
} while (num < 3); // شرط false ولی یک بار اجرا شد!
// مثال کاربردی — تا کاربر عدد درست وارد کند:
let guess;
do {
guess = 7; // در واقعیت: از کاربر بگیرید
} while (guess !== 7);
console.log("درست حدس زدید!");
حلقه for...of
برای پیمایش مقادیر یک شیء تکرارپذیر (آرایه، رشته، Map، Set و...):
// روی آرایه:
const fruits = ["سیب", "موز", "پرتقال"];
for (const fruit of fruits) {
console.log(fruit);
}
// روی رشته (حرف به حرف):
for (const char of "سلام") {
console.log(char); // س ل ا م
}
// روی Map:
const colors = new Map([
["red", "قرمز"],
["blue", "آبی"]
]);
for (const [en, fa] of colors) {
console.log(en, "=", fa);
}
حلقه for...in
برای پیمایش کلیدها (نام ویژگیهای) یک شیء:
const user = {
name: "علی",
age: 25,
city: "تهران"
};
for (const key in user) {
console.log(key, ":", user[key]);
}
// name : علی
// age : 25
// city : تهران
// هشدار: for...in کلیدهای ارثبریشده را هم میگیرد
// برای آرایه از for...of استفاده کنید نه for...in!
break — توقف حلقه
اجرای حلقه را کاملاً متوقف میکند:
// پیدا کردن اولین عدد زوج:
const numbers = [1, 3, 5, 8, 10, 7];
for (const num of numbers) {
if (num % 2 === 0) {
console.log("اولین زوج:", num); // 8
break; // دیگر ادامه نده
}
console.log("فرد:", num);
}
continue — پرش از تکرار
تکرار فعلی را رها میکند و به تکرار بعدی میرود:
// چاپ فقط اعداد فرد:
for (let i = 1; i <= 10; i++) {
if (i % 2 === 0) {
continue; // زوجها را رد کن
}
console.log(i); // 1 3 5 7 9
}
حلقههای تو در تو
حلقه داخل حلقه — برای کار با دادههای دوبعدی (مثل جدول یا ماتریس):
// جدول ضرب 3×3:
for (let i = 1; i <= 3; i++) {
let row = "";
for (let j = 1; j <= 3; j++) {
row += (i * j) + "\t";
}
console.log(row);
}
// پیمایش ماتریس:
const matrix = [
[1, 2, 3],
[4, 5, 6]
];
for (const row of matrix) {
for (const cell of row) {
console.log(cell);
}
}
// نکته: break فقط داخلیترین حلقه را میشکند
// برای شکستن هر دو، از label استفاده کنید:
outer: for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (i * j > 2) break outer;
console.log(i, j);
}
}
تکرار روی آرایهها
راههای مختلف پیمایش آرایه:
const items = ["a", "b", "c"];
// 1) for کلاسیک — دسترسی به index:
for (let i = 0; i < items.length; i++) {
console.log(i, items[i]);
}
// 2) for...of — فقط مقدار:
for (const item of items) {
console.log(item);
}
// 3) entries() — هم index هم مقدار:
for (const [index, item] of items.entries()) {
console.log(index, item);
}
Iterable — تکرارپذیر
شیئی که قابل پیمایش با for...of است Iterable نامیده میشود. این اشیا متد Symbol.iterator دارند:
// آرایه یک Iterable است:
const arr = [1, 2, 3];
console.log(typeof arr[Symbol.iterator]); // "function"
// ساخت یک Iterable سفارشی:
const myIterable = {
[Symbol.iterator]() {
let step = 0;
return {
next() {
step++;
if (step <= 3) {
return { value: step * 10, done: false };
}
return { done: true };
}
};
}
};
for (const val of myIterable) {
console.log(val); // 10 20 30
}
Iterator — پیمایشگر
شیئی که متد next() دارد و آبجکتی با value و done برمیگرداند:
const arr = ["الف", "ب", "پ"];
const iterator = arr[Symbol.iterator]();
console.log(iterator.next()); // { value: "الف", done: false }
console.log(iterator.next()); // { value: "ب", done: false }
console.log(iterator.next()); // { value: "پ", done: false }
console.log(iterator.next()); // { value: undefined, done: true }
Iterator Protocol
قراردادی که شیء باید رعایت کند تا قابل پیمایش باشد:
- متد
next()داشته باشد - آبجکتی با دو ویژگی برگرداند:
value(مقدار فعلی) وdone(آیا تمام شد؟) - وقتی
done: trueباشد، پیمایش تمام است
// یک Iterator دستی:
function createRangeIterator(start, end) {
let current = start;
return {
next() {
if (current <= end) {
return { value: current++, done: false };
}
return { value: undefined, done: true };
}
};
}
const it = createRangeIterator(1, 3);
console.log(it.next()); // { value: 1, done: false }
console.log(it.next()); // { value: 2, done: false }
console.log(it.next()); // { value: 3, done: false }
console.log(it.next()); // { done: true }
Async Iterator
پیمایشگر ناهمگام — برای دادههایی که با تأخیر میآیند (مثل درخواستهای شبکه). متد next() یک Promise برمیگرداند:
// ساخت Async Iterator:
async function* fetchPages() {
let page = 1;
while (page <= 2) {
// در واقعیت: const res = await fetch(`/api/page/${page}`);
const data = await new Promise(resolve => {
setTimeout(() => resolve(`صفحه ${page}`), 100);
});
yield data;
page++;
}
}
// پیمایش با for await...of:
(async () => {
for await (const page of fetchPages()) {
console.log(page); // صفحه 1، صفحه 2
}
})();
Async Iterable
شیئی که Symbol.asyncIterator دارد و با for await...of پیمایش میشود:
const asyncIterable = {
[Symbol.asyncIterator]() {
let i = 0;
return {
async next() {
if (i < 3) {
await new Promise(r => setTimeout(r, 50));
return { value: i++, done: false };
}
return { done: true };
}
};
}
};
(async () => {
for await (const num of asyncIterable) {
console.log(num); // 0 1 2
}
})();
کدام حلقه را انتخاب کنیم؟
| حلقه | کاربرد |
|---|---|
| for | تعداد تکرار مشخص، نیاز به index |
| while | تکرار تا برقراری شرط (تعداد نامشخص) |
| do...while | حداقل یک بار اجرا لازم است |
| for...of | پیمایش مقادیر Iterable (آرایه، رشته، Map...) |
| for...in | پیمایش کلیدهای شیء |
| for await...of | پیمایش Async Iterable (دادههای ناهمگام) |
جمعبندی
- for برای تعداد مشخص، while برای شرط، do...while برای حداقل یک اجرا
- for...of مقادیر را میدهد، for...in کلیدها را
- break حلقه را میشکند، continue تکرار را رد میکند
- Iterable شیء قابل پیمایش است، Iterator ابزار پیمایش با next()
- برای دادههای ناهمگام از Async Iterator و for await...of استفاده کنید
این مبحث بخشی از دوره آموزش کامل جاوا اسکریپت است.