1 September 2021

Perulangan: while dan for

Kita sering perlu untuk mengulangi tindakan.

Contohnya, Mengeluarkan barang dari sebuah daftar satu per satu atau hanya menjalankan kode yang sama untuk setiap nomor dari 1 hingga 10.

Perulangan adalah sebuah cara untuk mengulangi kode yang sama beberapa kali.

Perulangan “while”

Perulangan while memiliki sintaks sebagai berikut:

while (kondisi) {
  // kode
  // disebut "badan perulangan"
}

Ketika kondisi bernilai truthy, kode dari badan perulangan dijalankan.

Contohnya, perulangan di bawah mengeluarkan i selagi i < 3:

let i = 0;
while (i < 3) { // menampilkan 0, lalu 1, lalu 2
  alert( i );
  i++;
}

Eksekusi tunggal dari badan perulangan disebut sebuah pengulangan. Perulangan pada contoh diatas membuat tiga kali pengulangan.

Jika i++ hilang dari contoh di atas, perulangan akan mengulangi (dalam teori) secara terus-menerus. Pada praktiknya, browser menyediakan cara untuk menghentikan perulangan, dan pada sisi server JavaScript, kita dapat mematikan prosesnya.

Ekspresi atau variable apapun bisa menjadi sebuah kondisi perulangan, tidak hanya perbandingan: kondisi terevalusasi dan terkonversi menjadi boolean oleh while.

Contohnya, cara cepat untuk menulis while (i != 0) adalah while (i):

let i = 3;
while (i) { // ketika i menjadi 0, kondisi bernilai salah, dan perulangan berhenti
  alert( i );
  i--;
}
Kurung kurawal tidak dibutuhkan untuk badan baris tunggal

Jika badan perulangan mempunyai sebuah pernyataan tunggal, kita dapat menghilangkan kurung kurawal {…}:

let i = 3;
while (i) alert(i--);

Perulangan “do…while”

Pengecekan kondisi dapat dipindahkan di bawah badan perulangan menggunakan do..while sintaks:

do {
  // badan perulangan
} while (condition);

Perulangan akan mengeksekusi badan terlebih dahulu, lalu memeriksa kondisi, dan, selagi itu bernilai truthy, jalankan itu lagi dan lagi.

Contohnya:

let i = 0;
do {
  alert( i );
  i++;
} while (i < 3);

Format penulisan ini hanya digunakan ketika kamu ingin badan dari perulangan tereksekusi setidaknya sekali Terlepas dari kondisi menjadi bernilai benar. Biasanya, format lain yang dipilih: while(…) {…}.

Perulangan “for”

Perulangan for lebih complex, tapi merupakan perulangan yang paling umum digunakan.

Itu terlihat seperti ini:

for (awal; kondisi; langkah) {
  // ... badan perulangan ...
}

Mari belajar makna dari bagian ini dari contoh. Perulangan dibawah menjalankan alert(i) untuk i dari 0 sampai dengan (tapi tidak termasuk) 3:

for (let i = 0; i < 3; i++) { // menampilkan 0, lalu 1, lalu 2
  alert(i);
}

Mari bahas pernyataan for bagian demi bagian:

bagian
begin i = 0 Jalankan sekali masuk ke loop.
condition i < 3 Cek sebelum tiap iterasi loop. Jika salah, loop berhenti.
body alert(i) Jalankan lagi dan lagi selama kondisi bernilai truthy.
step i++ Exekusi setelah badan di tiap iterasi.

Cara kerja algoritma perulangan umum seperti ini:

Jalankan begin
→ (jika condition → jalankan body dan jalankan step)
→ (jika condition → jalankan body dan jalankan step)
→ (jika condition → jalankan body dan jalankan step)
→ ...

Dikatakan, begin diexekusi sekali, kemudian ia beriterasi: setelah tiap condition dites, body dan step diexekusi.

Jika kamu baru pada perulangan, ini bisa membantumu kembali ke contoh dan mereproduksi bagamana ini berjalan selangkah demi selangkah pada sebuah selembar kertas.

Inilah yang sebenarnya terjadi pada kasus kita:

// for (let i = 0; i < 3; i++) alert(i)

// jalankan awal
let i = 0
// jika kondisi → jalankan badan dan jalankan langkah
if (i < 3) { alert(i); i++ }
// jika kondisi → jalankan badan dan jalankan langkah
if (i < 3) { alert(i); i++ }
// jika kondisi → jalankan badan dan jalankan langkah
if (i < 3) { alert(i); i++ }
// ...selesai, karena sekarang i == 3
Deklarasi varibel sebaris

Disini, “penghitung” variabel i dideklarasikan di dalam perulangan. Ini disebut deklarasi variabel “sebaris”. variabel ini hanya akan terlihat di dalam perulangan.

for (let i = 0; i < 3; i++) {
  alert(i); // 0, 1, 2
}
alert(i); // error, tidak ada variabel

Daripada mendefinisikan sebuah variabel, kita dapat menggunakan yang sudah ada:

let i = 0;

for (i = 0; i < 3; i++) { // gunakan variabel yang sudah ada
  alert(i); // 0, 1, 2
}

alert(i); // 3, terlihat, karena dideklarasikan diluar dari perulangan

Melewatkan bagian

Bagian apapun dari for dapat dilewati.

Contoh, kita dapat menghilangkan awal jika kita tidak butuh untuk melakukan apapun pada awal perulangan.

Seperti ini:

let i = 0; // kita punya i yang sudah dideklarasikan dan telah ditetapkan

for (; i < 3; i++) { // tidak butuh "awal"
  alert( i ); // 0, 1, 2
}

Kita juga bisa menghilangkan bagian langkah:

let i = 0;

for (; i < 3;) {
  alert( i++ );
}

Ini membuat perulangan sama dengan while (i < 3).

Kita sebenarnya dapat menghilangkan semuanya, membuat sebuah perulangan tak terhingga:

for (;;) {
  // ulangi tanpa batas
}

Tolong dicatat bahwa dua for titik koma ; harus ada, jika tidak, akan ada sintaks error.

Menghentikan perulangan

Biasanya, sebuah perulangan keluar ketika kondisinya menjadi bernilai salah.

Tapi kita dapat memaksanya keluar pada waktu apapun menggunakan perintah spesial break.

Contohnya, perulangan dibawah menanyakan pengguna untuk serangkaian angka, “hentikan” ketika tidak ada angka yang dimasukan:

let sum = 0;

while (true) {

  let value = +prompt("Masukan sebuah angka", '');

  if (!value) break; // (*)

  sum += value;

}
alert( 'Sum: ' + sum );

Perintah break teraktivasi pada baris (*) jika pengguna memasukan baris kosong atau membatalkan input. itu akan langsung berhenti, melewati kontrol ke baris pertama setelah perulangan. yang bernama, alert.

Kombinasi “perulangan tak terhingga + break sesuai kebutuhan” bagus untuk situasi dimana sebuah kondisi perulangan harus diperiksa tidak di awal atau akhir dari perulangan, tapi di pertengahan atau bahkan di beberapa tempat tubuhnya.

Lanjutkan ke perulangan berikutnya

Perintah continue adalah “versi ringan” dari break. Ini tidak mengentikan keseluruhan perulangan. sebagai gantinya, ini menghentikan perulangan saat ini dan memaksa perulangan untuk memulai yang baru (jika kondisi diperbolehkan).

Kita dapat menggunakan ini jika kita selesai dengan perulangan saat ini dan ingin pindah ke yang berikutnya.

Perulangan dibawah menggunakan continue untuk hanya menampilkan nilai ganjil:

for (let i = 0; i < 10; i++) {

  // jika benar, lewati bagian badan perulangan yang tersisa
  if (i % 2 == 0) continue;

  alert(i); // 1, then 3, 5, 7, 9
}

Untuk nilai genap dari i, perintah continue mengentikan menjalankan badan dan melewati kontrol ke perulangan for berikutnya (dengan nomor berikutnya). jadi alert hanya terpanggil untuk nilai ganjil.

Perintah continue membantu mengurangi penyarangan

Sebuah perulangan yang menampilkan nilai ganjil dapat terlihat seperti ini:

for (let i = 0; i < 10; i++) {

  if (i % 2) {
    alert( i );
  }

}

Dari sudut pandang teknis, ini identik dengan contoh diatas. Tentunya, kita dapat membungkus kode dalam sebuah blok if daripada menggunakan continue.

Tapi sebagai efeknya, hal ini akan menciptakan kode lebih dalam satu tingkat (pemanggilan alert didalam kurung kurawal). Jika kode didalam if lebih panjang beberapa baris, hal itu akan membuat tingkat keterbacaan kode menjadi berkurang.

Tidak ada break/continue ke sisi kanan ‘?’

Harap perhatikan bahwa sintaks yang membangun yang bukan ekspresi tidak dapat digunakan dengan operator ternary ?. Khususnya, perintah seperti break/continue tidak diperbolehkan.

Misalnya, jika kita mengambil kode ini:

if (i > 5) {
  alert(i);
} else {
  continue;
}

…dan tulis ulang menggunakan sebuah tanda tanya:

(i > 5) ? alert(i) : continue; // continue tidak diperbolehkan disini

…ia berhenti jalan: ada galat syntax:

Ini hanya alasan lain untuk tidak menggunakan operator tanda tanya ? daripada if.

Label untuk break/continue

Terkadang kita perlu keluar dari beberapa perulangan bersarang sekaligus.

Misalnya, dalam kode di bawah kita lakukan perulangan terhadap i dan j, meminta koordinat (i, j) dari (0,0) ke(3,3):

for (let i = 0; i < 3; i++) {

  for (let j = 0; j < 3; j++) {

    let input = prompt(`Nilai pada koordinasi (${i},${j})`, '');

    // bagaimana jika saya ingin keluar dari sini ke Done (dibawah)?
  }
}

alert('Done!');

Kita butuh cara untuk menghentikan proses jika pengguna membatalkan input.

break biasa setelah input hanya akan menghentikan perulangan dalam. Itu tidak cukup–label, datang untuk menyelamatkan!

Label adalah sebuah pengidentifikasi dengan sebuah titik dua sebelum perulangan:

labelName: for (...) {
  ...
}

Pernyataan break <labelName> di dalam loop di bawah menghentikan pada label:

outer: for (let i = 0; i < 3; i++) {

  for (let j = 0; j < 3; j++) {

    let input = prompt(`Value at coords (${i},${j})`, '');

    // jika sebuah string kosong atau terbatalkan, lalu hentikan kedua perulangan
    if (!input) break outer; // (*)

    // lakukan sesuatu dengan nilai...
  }
}
alert('Done!');

Pada kode diatas, break outer melihat keatas untuk label bernama outer dan menghentikan perulangan itu.

Jadi kontrol pergi langsung dari (*) ke alert('Done!').

Kita juga dapat memindah label ke sebuah baris terpisah:

outer:
for (let i = 0; i < 3; i++) { ... }

Perintah continue dapat juga digunakan dengan sebuah label. pada kasus ini, eksekusi kode berpindah ke perulangan label berikutnya.

Label tidak mengizinkan “lompat” ke manapun

Label tidak mengizinkan kita untuk lompat ke sembarang tempat dalam kode.

Misalnya, mustahil melakukan ini:

break label;  // tidak lompak ke label di bawah

label: for (...)

Direktif break harus berada di dalam blok kode. Secara teknis, setiap blok kode berlabel akan dilakukan, contoh.:

label: {
  // ...
  break label; // berjalan
  // ...
}

…Meskipun, 99,9% dari waktu break yang digunakan adalah loop dalam, seperti yang telah kita lihat pada contoh di atas.

continue hanya dimungkinkan dari dalam loop.

Ringkasan

Kita membahas 3 jenis perulangan:

  • while – Kondisi diperiksa sebelum setiap perulangan.
  • do..while – Kondisi diperiksa setelah setiap perulangan.
  • for (;;) – Kondisi diperiksa sebelum setiap perulangan, pengaturan tambahan tersedia.

Untuk membuat sebuah perulangan “tak terhinggaa”, biasanya konstruksi while(true) digunakan. Demikian sebuah perulangan, seperti yang lainnya, dapat berhenti dengan perintah break.

Jika kita tidak ingin melakukan apapun di perulangan saat ini dan ingin meneruskan ke yang berikutnya, kita dapat menggunakan perintah continue.

break/continue mendukung label sebelum perulangan. Label adalah satu-satunya cara untuk break/continue menghindari loop bersarang untuk pergi ke luar

Tugas

pentingnya: 3

Apa nilai terakhir yang diperingatkan oleh kode ini? Mengapa?

let i = 3;

while (i) {
  alert( i-- );
}

Jawabannya: 1.

let i = 3;

while (i) {
  alert( i-- );
}

Setiap pengulangan mengurangi i dengan 1. pengecekan while(i) menghentikan perulangan ketika i = 0.

Oleh karena itu, langkah-langkah perulangan membentuk urutan sebagai berikut (“loop unrolled”):

let i = 3;

alert(i--); // menampilkan 3, mengurangi i menjadi 2

alert(i--) // menampilkan 2, mengurangi i menjadi 1

alert(i--) // menampilkan 1, mengurangi i menjadi 0

// selesai, pengecekan while(i) menghentikan pengulangan
pentingnya: 4

Untuk setiap iterasi, tulis nilai mana yang dikeluarkan dan bandingkan dengan solusinya.

Kedua perulangan alert nilai yang sama, atau tidak?

  1. Bentuk prefix ++i:

    let i = 0;
    while (++i < 5) alert( i );
  2. Bentuk postfix i++

    let i = 0;
    while (i++ < 5) alert( i );

Tugas mendemonstrasikan bagaimana bentuk postfix/prefix dapat menyebabkan hasil yang berbeda ketika digunakan dalam perbandingan

  1. Dari 1 ke 4

    let i = 0;
    while (++i < 5) alert( i );

    nilai pertama adalah i = 1, karena ++i menambah terlebih dahulu i dan mengembalikan nilai baru. Jadi perbandingan pertama adalah 1 < 5 dan alert menampilkan 1.

    lalu diikuti 2, 3, 4… – nilainya muncul satu per satu. Perbandingan selalu menggunakan nilai yang ditambah, karna ada ++ sebelum variabel.

    Akhirnya, i = 4 bertambah menjadi 5, perbandingan while(5 < 5) gagal, dan pengulangan berhenti. Jadi 5 tidak ditampilkan.

  2. Dari 1 ke 5

    let i = 0;
    while (i++ < 5) alert( i );

    Lagi, nilai pertama adalah i = 1. bentuk postfix dari i++ menambah i dan kemudian mengembalikan nilai yang lama, jadi perbandingan i++ < 5 akan menggunakan i = 0 (berbeda dengan ++i < 5).

    Namun panggilan alert terpisah. ini adalah pernyataan lain yang berjalan setelah pertambahan dan perbandingan. Jadi ini mendapatkan nilai yang saat ini i = 1.

    Lalu diikuti 2, 3, 4…

    Mari berhenti di i = 4. bentuk prefix ++i akan menaikannya dan menggunakan 5 di perbandingan. Tapi disini kita mempunyai bentuk postfix i++. jadi ini menambah i menjadi 5, namun mengembalikan nilai yang lama. Karna perbandingan yang sebenarnya adalah while(4 < 5) – benar, dan kontrol berlanjut ke alert.

    Nilai i = 5 adalah yang terkahir, karena pada langkah berikutnya while(5 < 5) adalah salah.

pentingnya: 4

Untuk setiap perulangan tulis nilai mana yang akan ditampilkan. lalu bandingkan dengan jawabanya

Kedua perulangan alert nilai yang sama atau tidak?

  1. Bentuk postfix:

    for (let i = 0; i < 5; i++) alert( i );
  2. Bentuk prefix:

    for (let i = 0; i < 5; ++i) alert( i );

Jawabanya: dari 0 ke 4 pada kedua kasus.

for (let i = 0; i < 5; ++i) alert( i );

for (let i = 0; i < 5; i++) alert( i );

Itu dapat dengan mudah dikurangkan dari algoritma for:

  1. Jalankan sekali i = 0 sebelum apapun (begin).
  2. Cek kondisinya i < 5
  3. Jika true – jalankan loop body alert(i), dan kemudian i++

pertambahan i++ terpisah dari pengecekan kondisi (2). itu hanya pernyataan lain.

Nilai yang dikembalikan oleh pertambahan tidak digunakan disini, jadi tidak ada bedanya antara i++ dan ++i.

pentingnya: 5

Gunakan perulangan for untuk menghasilkan angka genap dari 2sampai 10.

jalankan demonya

for (let i = 2; i <= 10; i++) {
  if (i % 2 == 0) {
    alert( i );
  }
}

Kita menggunakan operator “modulo” % untuk mendapatkan nilai sisa dan untuk mengecek kegenapan disini.

pentingnya: 5

Tulis ulang kode ubah perulangan for ke while tanpa mengubah perilakunya (hasilnya harus tetap sama).

for (let i = 0; i < 3; i++) {
  alert( `number ${i}!` );
}
let i = 0;
while (i < 3) {
  alert( `number ${i}!` );
  i++;
}
pentingnya: 5

Tulis sebuah perulangan yang meminta angka lebih dari 100. Jika pendatang memasukan angka lainnya – tanya mereka untuk menginput kembali.

Perulangan harus menanyakan untuk sebuah angka sampai pengunjung memasukan angka lebih dari 100 atau membatalkan input/memasukan sebuah baris kosong.

Disini kita dapat menganggap bahwa pengunjung hanya menginput angka. Tidak perlu menerapkan penanganan spesial untuk input non-numerik di tugas ini.

jalankan demonya

let num;

do {
  num = prompt("Masukan angka lebih dari 100?", 0);
} while (num <= 100 && num);

Perulangan do..while diulangi selagi kedua cek itu bernilai benar:

  1. Pengecekan untuk num <= 100 – itu adalah, nilai yang dimasukan masih tidak lebih besar dari 100.
  2. Pengecekan && num adalah salah ketika num adalah null atau sebuah string kosong. kemudian perulangan while berhenti juga.

P.S. Jika num adalah null lalu num <= 100 adalah true, jadi tanpa pengecekan kedua, perulangan tidak akan berhenti jika pengguna mengeclick CANCEL. Kedua pengecekan dibutuhkan.

pentingnya: 3

Angka integer lebih dari 1 disebut bilangan prima jika itu tidak bisa dibagi tanpa sisa oleh siapapun kecuali 1 dan bilangan itu sendiri.

Dengan kata lain, n > 1 adalah prima jika tidak dapat dibagi secara merata oleh apapun kecuali 1 dan n.

Contohnya, 5 adalah prima, karna tidak bisa dibagi tanpa sisa oleh 2, 3 dan 4.

Tulis kode yang menghasilkan bilangan prima dalam interval dari 2 sampai n.

Untuk n = 10 hasilnya akan 2,3,5,7.

P.S. Kode harus bekerja untuk segala n, tidak disetel untuk nilai tetap apapun.

Ada banyak algoritma untuk tugas ini.

Mari gunakan perulangan bersarang:

For each i in the interval {
  cek if i has a divisor from 1..i
  if yes => the value is not a prime
  if no => the value is a prime, show it
}

Kode menggunakan label:

let n = 10;

nextPrime:
for (let i = 2; i <= n; i++) { // untuk setiap i...

  for (let j = 2; j < i; j++) { // mencari pembagi..
    if (i % j == 0) continue nextPrime; // bukan prima, pergi ke i berikutnya
  }

  alert( i ); // prima
}

Ada banyak ruang untuk mengoptimalkannya. Misalnya, kita dapat mencari pembagi dari 2 ke akar kuadrat dari i. Tapi bagaimanapun, jika kita ingin sangat efisien untuk interval besar, kita perlu mengubah pendekatan dan mengandalkan matematika lanjutan dan algotima rumit seperti Quadratic sieve, General number field sieve dsb.

Peta tutorial