بازگشت به دوره

ساختارهای تکرار - بخش دوم

حلقه‌ها و آرایه‌ها

یکی از کارهای معمول در برنامه‌نویسی، اجرای مجموعه‌ای از دستورات بر روی عناصر یک آرایه است. مثلاً فرض کنید آرایه‌ای داریم که تمام عناصر آن عدد هستند. حال می‌خواهیم تمام این اعداد را دو برابر کنیم. برای این کار می‌توانیم از حلقه‌ها استفاده کنیم.


let numbers = [3 , 5  , 1 , 11 , 14 , 2];
for(let i = 0 ; i < numbers.length ; i++){
	numbers[i] *=  2;				// or   numbers[i] = numbers[i] * 2;
}
numbers;
← [6 , 10 , 2 , 22 , 28 , 4]

در مثال فوق ابتدا آرایه‌ای از اعداد تعریف شده است. سپس یک حلقه‌ی for ایجاد شده است که به تعداد عناصر این آرایه تکرار خواهد شد. با توجه به این که اندیس عناصر آرایه‌ها از صفر شروع می‌شود، متغیر i در ابتدا برابر با صفر قرار داده شده است. همچنین شرط i < numbers.length نیز موجب می‌شود تا دستورات این حلقه تا قبل از رسیدن متغیر i به مقدار طول آرایه ادامه پیدا کنند. در نتیجه این حلقه دقیقاً به اندازه‌ی طول آرایه تکرار شده و در هر تکرار مقدار متغیر i برابر با اندیس یکی از عناصر این آرایه خواهد بود.

تنها دستور موجود در این حلقه نیز به ازای هر عنصر از این آرایه یک بار اجرا شده و مقدار آن عنصر را دو برابر می‌کند. در نتیجه پس از پایان تکرارهای این حلقه، مقدار تمام عناصر این آرایه دو برابر شده است.

 

ساختار تکرار for-of

یکی دیگر از ساختارهای تکرار در جاوا اسکریپت، ساختار for-of است. با استفاده از این ساختار می‌توان مجموعه‌ای از دستورات را بر روی تمام عناصر یک آرایه، و یا تمام اعضای یک مجموعه یا یک نقشه اعمال کرد. ابتدا این ساختار را بر روی آرایه‌ها به کار می‌بریم.


let fruits = ['Apple' , 'Orange' , 'Banana' , 'Cherry'];
for(let value of fruits){
	console.log(value);
}

در صورت اجرای برنامه‌ی فوق، خروجی زیر تولید خواهد شد. (این برنامه را می‌توانید اینجا اجرا کنید)


← Apple
← Orange
← Banana
← Cherry

زمانی که ساختار for-of را مانند مثال فوق بر روی یک آرایه به کار می‌بریم. حلقه‌ی ایجاد شده دقیقاً به تعداد عناصر آرایه تکرار می‌شود و در هر تکرار مقدار یکی از عناصر آرایه در متغیر value قرار می‌گیرد که در مجموعه‌ی دستورات داخل حلقه می‌توان از مقدار این متغیر برای اهداف مختلف استفاده کرد. همچنین توجه کنید نام این متغیر دلخواه است و از هر شناسه‌ی معتبر دیگری نیز می‌توان به جای value استفاده کرد. در مثال فوق تنها دستور داخل حلقه موجب چاپ شدن یکی از عناصر آرایه در کنسول می‌شود.

 

ساختار for-of و مجموعه‌ها

با استفاده از ساختار for-of می‌توان به سادگی حلقه‌هایی را بر روی مجموعه‌ها نیز ایجاد کرد. یعنی مجموعه‌ای از دستورات را به ازای تک تک اعضای یک مجموعه اجرا کرد. به مثال زیر توجه کنید.


let fruits = new Set(['Apple' , 'Orange' , 'Banana' , 'Cherry']);
for(let value of fruits){
	console.log(value);
}

این برنامه را می‌توانید اینجا اجرا کنید. پس از اجرا خواهید دید که همان خروجی که در مثال قبلی دیدیم تولید می‌شود. لذا نحوه‌ی استفاده از ساختار for-of بر روی مجموعه‌ها کاملاً مشابه آرایه‌ها است.

 

ساحتار for-of و نقشه‌ها

ساختار for-of را بر روی نقشه‌ها نیز می‌توان به کار برد. اما روش استفاده از این ساختار بر روی نقشه‌ها کمی متفاوت است. زیرا بر خلاف آرایه‌ها و مجموعه‌ها که هر عضو در آنها دارای یک مقدار است. در نقشه‌ها هر عضو دارای دو بخش کلید و مقدار یا key و value است. به همین دلیل در زمان استفاده از for-of با توجه به این که دستورات داخل حلقه بر روی کدام یک از این دو مورد (یا هر دو مورد) اجرا می‌شوند، روش استفاده متفاوت خواهد بود.

در صورتی که قصد اجرای دستورات مورد نظر را بر روی کلیدهای اعضا داشته باشیم، می‌توان به صورت زیر عمل کرد.


let person = new Map([ ['firstName' , 'Abbas'] , ['lastName' , 'Moqaddam'] , ['age' , 33] ]);
for(let key of person.keys()){
	console.log(key);
}

در صورت اجرای برنامه‌ی فوق خروجی زیر تولید می‌شود. همانطور که مشاهده می‌کنید در هر تکرار، کلید یکی از اعضای نقشه در متغیر key قرار می‌گیرد و داخل حلقه نیز همین کلید در کنسول چاپ می‌شود. (این برنامه را می‌توانید اینجا اجرا کنید)


← firstname
← lastname
← age

اما اگر در دستورات یک حلقه، به مقدار اعضای یک نقشه نیاز داشته باشیم، می‌توان ساختار for-of را به شکل زیر به کار برد.


let person = new Map([ ['firstName' , 'Abbas'] , ['lastName' , 'Moqaddam'] , ['age' , 33] ]);
for(let value of person.values()){
	console.log(value);
}

در مثال فوق در هر تکرار مقدار یکی از اعضای نقشه در متغیر value قرار می‌گیرد. بنابراین با اجرای برنامه‌ی فوق خروجی زیر تولید خواهد شد. (این برنامه را می‌توانید اینجا اجرا کنید)


← Abbas
← Moqaddam
← 33

همچنین اگر در دستورات داخل حلقه، هم به کلیدها و هم به مقادیر اعضای یک نقشه نیاز داشته باشید، می‌توانید از ساختار for-of به شکل زیر استفاده کنید.


let person = new Map([ ['firstName' , 'Abbas'] , ['lastName' , 'Moqaddam'] , ['age' , 33] ]);
for(let [key , value] of person.entries()){
	console.log(key + " = " + value);
}

با اجرای برنامه‌ی فوق خروجی زیر تولید می‌شود که در هر خط، کلید و مقدار یک عضو از نقشه را نمایش می‌دهد. (این برنامه را می‌توانید اینجا اجرا کنید)


← firstname = Abbas
← lastname = Moqaddam
← age = 33
 

break و continue در حلقه‌ها

زمانی که با حلقه‌ها سر و کار داریم. در برخی شرایط خاص ممکن است لازم باشد که اجرای حلقه را به طور کامل پایان دهیم و یا اجرای تکرار فعلی را پایان داده و تکرار بعدی را آغاز کنیم. در چنین شرایطی می‌توان از دستورات break و continue استفاده کرد.

اجرای دستور break در یک حلقه، موجب توقف اجرای دستورات و خروج کامل از آن حلقه می‌شود. به قطعه کد زیر توجه کنید.


for(let i = 0 ; i < 10 ; i++){
	if(i == 4){
		break;
	}
	console.log(i);
}

اجرای دستورات فوق خروجی زیر را تولید می‌کند. (این برنامه را می‌توانید اینجا اجرا کنید)


← 0
← 1
← 2
← 3

همانطور که مشاهده می‌کنید، حلقه‌ی ایجاد شده فقط ۴ بار اجرا می‌شود و ۴ بار خروجی چاپ می‌کند. این رفتار به دلیل استفاده از دستور break بروز کرده است. در هر تکرار از حلقه‌ی فوق، با استفاده از ساختار شرطی if، مقدار متغیر i بررسی می‌شود. در صورتی که مقدار این متغیر برابر با ۴ باشد، دستور break اجرا می‌شود که موجب خروج کامل از حلقه می‌شود. در نتیجه پس از ۴ بار اجرای دستورات، وقتی که در تکرار پنجم مقدار متغیر i به ۴ می‌رسد. شرط i == 4 برقرار است و دستور break اجرا می‌شود. به همین دلیل فقط اعداد 0 تا 3 در خروجی چاپ می‌شوند.

توجه کنید که در مثال فوق در صورتی که دستور چاپ را قبل از ساختار شرطی if قرار دهیم، عدد ۴ نیز در خروجی چاپ خواهد شد. چرا که دستور break بعد از چاپ شدن مقدار متغیر i اجرا می‌شود. به قطعه کد زیر توجه کنید.


for(let i = 0 ; i < 10 ; i++){
	console.log(i);
	if(i == 4){
		break;
	}
}

خروجی کد فوق به صورت زیر خواهد بود.


← 0
← 1
← 2
← 3
← 4

دستور continue نیز موجب توقف اجرای دستورات می‌شود. اما برخلاف دستور break، اجرای حلقه را به پایان نمی‌رساند. بلکه اجرای دستورات را در تکرار فعلی متوقف می‌کند و تکرار بعدی را شروع می‌کند. البته شروع تکرار بعدی در صورتی رخ می‌دهد که شرط اجرای حلقه همچنان برقرار باشد. یعنی قبل از شروع تکرار بعدی، شرط ادامه‌ی حلقه بررسی می‌شود و در صورت برقرار بودن شرط، تکرار بعدی شروع می‌شود. همچنین اگر دستور continue در حلقه‌ی for به کار رفته باشد، قبل از شروع تکرار بعدی قسمت after اجرا می‌شود، سپس شرط ادامه بررسی می‌شود. به مثال زیر توجه کنید.


for(let i = 0 ; i < 10 ; i++){	
	if(i == 8){
		break;
	}else if(i % 2 == 0){
		continue;
	}else{
		console.log(i);
	}
}

اجرای برنامه‌ی فوق خروجی زیر را تولید می‌کند. (این برنامه را می‌توانید اینجا اجرا کنید)


← 1
← 3
← 5
← 7
در این مثال، در هر تکرار از حلقه‌ی for شرایط زیر بررسی می‌شوند.

با توجه به شرایط فوق دستورات داخل حلقه فقط ۸ بار اجرا می‌شوند. همچنین در این ۸ بار اجرا شدن دستورات، اگر مقدار i زوج باشد اجرای حلقه در همان نقطه متوقف شده و تکرار بعدی آغاز می‌شود. در نتیجه مقادیر زوج متغیر i هیچگاه در خروجی نمایش داده نمی‌شود. بنابراین فقط اعداد فرد بین 0 تا 8 در خروجی چاپ می‌شوند.

نکته : در مثال‌های فوق فقط از حلقه‌های for استفاده شد. ولی دستورات break و continue در تمام ساختارهای تکرار همین رفتار را دارند.

نکته : در صورتی که در حلقه‌های تو در تو از دستورات break و continue در حلقه‌های داخلی استفاده کنیم. فقط اجرای حلقه‌ی داخلی متوقف می‌شود و اجرای حلقه‌ی خارجی روند طبیعی خود را طی می‌کند.

در فصل بعدی این کتاب به مبحث بسیار با اهمیت و پر کاربرد توابع (Functions) می‌پردازیم.