Bab 2 dari Eloquent JavaScript. Sebelumnya: 01 Nilai, Tipe, dan Operator. Berikutnya: 03 Fungsi.

Dan jantungku menyala merah terang di balik kulitku yang tipis dan tembus pandang dan mereka harus nyuntikin 10cc JavaScript biar aku sadar lagi. (Aku merespons dengan baik terhadap racun di dalam darah.) Bung, barang itu bakal nendang buah persik keluar dari insangmu!

— _why, Why’s (Poignant) Guide to Ruby

Ilustrasi sejumlah tentakel memegang bidak catur

Di bab ini, kita bakal mulai ngelakuin hal-hal yang beneran bisa disebut pemrograman. Kita bakal memperluas penguasaan bahasa JavaScript kita lebih dari sekadar kata benda dan potongan kalimat yang udah kita lihat sejauh ini, sampai ke titik di mana kita bisa nulis prosa yang bermakna.

Ekspresi dan Statement

Di Bab 1, kita bikin nilai dan nerapin operator ke mereka buat dapet nilai baru. Bikin nilai kaya gini adalah substansi utama dari program JavaScript mana pun. Tapi substansi itu harus dibingkai dalam struktur yang lebih besar biar berguna. Itu yang bakal kita bahas di bab ini.

Potongan kode yang ngehasilin nilai disebut ekspresi (expression). Setiap nilai yang ditulis secara literal (kaya 22 atau "psychoanalysis") adalah ekspresi. Ekspresi di antara tanda kurung juga ekspresi, begitu juga operator binary yang diterapin ke dua ekspresi atau operator unary yang diterapin ke satu ekspresi.

Ini nunjukin sebagian keindahan dari antarmuka berbasis bahasa. Ekspresi bisa berisi ekspresi lain dengan cara yang mirip gimana anak kalimat di bahasa manusia bersarang, anak kalimat bisa berisi anak kalimatnya sendiri, dan seterusnya. Ini bikin kita bisa ngebangun ekspresi yang menggambarkan perhitungan serumit apa pun.

Kalau ekspresi setara dengan potongan kalimat, statement JavaScript setara dengan kalimat utuh. Program adalah daftar statement.

Jenis statement paling sederhana adalah ekspresi dengan titik koma setelahnya. Ini sebuah program:

1;
!false;

Tapi ini program yang gak berguna. Ekspresi bisa puas cuma dengan ngehasilin nilai, yang kemudian bisa dipakai kode yang ngelingkupinya. Tapi statement berdiri sendiri, jadi kalau dia gak ngaruh ke dunia, dia gak berguna. Dia mungkin nampilin sesuatu di layar, kaya console.log, atau ngubah keadaan mesin dengan cara yang bakal ngaruh ke statement-statement setelahnya. Perubahan ini disebut side effect (efek samping). Statement di contoh sebelumnya cuma ngehasilin nilai 1 dan true lalu langsung ngebuangnya. Ini gak ninggalin kesan apa pun ke dunia. Waktu kamu jalanin program ini, gak ada yang terjadi yang bisa diamati.

Di beberapa kasus, JavaScript ngebolehin kamu ngilangin titik koma di akhir statement. Di kasus lain, dia harus ada, atau baris berikutnya bakal diperlakukan sebagai bagian dari statement yang sama. Aturan kapan dia bisa dihilangkan dengan aman agak rumit dan rawan salah. Jadi di buku ini, setiap statement yang butuh titik koma bakal selalu dikasih. Saya nyaranin kamu ngelakuin hal yang sama, setidaknya sampai kamu belajar lebih banyak soal seluk-beluk titik koma yang hilang.

Binding

Gimana sebuah program nyimpen keadaan internal? Gimana dia ngingat sesuatu? Kita udah lihat cara ngehasilin nilai baru dari nilai lama, tapi ini gak ngubah nilai lamanya, dan nilai barunya harus langsung dipakai atau dia bakal buyar lagi. Buat nangkep dan megang nilai, JavaScript nyediain sesuatu yang disebut binding, atau variabel.

let caught = 5 * 5;

Itu ngasih kita jenis statement kedua. Kata khusus (keyword) let nunjukin bahwa kalimat ini bakal mendefinisikan sebuah binding. Dia diikuti nama bindingnya dan, kalau kita mau langsung ngasih dia nilai, diikuti operator = dan sebuah ekspresi.

Contoh tadi bikin binding bernama caught dan pakai dia buat nangkep angka yang dihasilin dari ngaliin 5 dengan 5.

Setelah sebuah binding didefinisikan, namanya bisa dipakai sebagai ekspresi. Nilai dari ekspresi kaya gitu adalah nilai yang lagi dipegang bindingnya saat ini. Ini contohnya:

let ten = 10;
console.log(ten * ten);
// → 100

Waktu sebuah binding nunjuk ke sebuah nilai, itu gak berarti dia terikat ke nilai itu selamanya. Operator = bisa dipakai kapan aja ke binding yang udah ada buat mutusin mereka dari nilai saat ini dan bikin mereka nunjuk ke nilai baru:

let mood = "light";
console.log(mood);
// → light
mood = "dark";
console.log(mood);
// → dark

Kamu sebaiknya ngebayangin binding sebagai tentakel, bukan kotak. Mereka gak berisi nilai; mereka menggenggam nilai, dua binding bisa nunjuk ke nilai yang sama. Sebuah program cuma bisa ngakses nilai-nilai yang masih dia punya referensinya. Kalau kamu perlu ngingat sesuatu, kamu bisa numbuhin tentakel buat megang itu atau mindahin salah satu tentakel yang udah ada ke situ.

Kita lihat contoh lain. Buat ngingat jumlah dolar yang masih diutang Luigi ke kamu, kamu bikin sebuah binding. Waktu dia bayar $35, kamu ngasih binding ini nilai baru.

let luigisDebt = 140;
luigisDebt = luigisDebt - 35;
console.log(luigisDebt);
// → 105

Waktu kamu mendefinisikan binding tanpa ngasih nilai, tentakelnya gak punya apa-apa buat digenggam, jadi dia berakhir di udara kosong. Kalau kamu minta nilai dari binding kosong, kamu bakal dapet nilai undefined.

Satu statement let bisa mendefinisikan beberapa binding. Definisinya harus dipisah pakai koma:

let one = 1, two = 2;
console.log(one + two);
// → 3

Kata var dan const juga bisa dipakai buat bikin binding, dengan cara yang mirip let.

var name = "Ayda";
const greeting = "Hello ";
console.log(greeting + name);
// → Hello Ayda

Yang pertama, var (singkatan dari “variable”), adalah cara binding dideklarasikan di JavaScript sebelum 2015, waktu let belum ada. Saya bakal balik ke perbedaan tepatnya dari let di bab berikutnya. Buat sekarang, ingat aja dia kebanyakan ngelakuin hal yang sama, tapi kita jarang bakal pakai dia di buku ini karena dia berperilaku aneh di beberapa situasi.

Kata const singkatan dari constant (konstanta). Dia mendefinisikan binding konstan, yang nunjuk ke nilai yang sama selama dia hidup. Ini berguna buat binding yang cuma ngasih nama ke sebuah nilai biar kamu bisa gampang ngerujuknya nanti.

Nama Binding

Nama binding bisa berupa deretan satu huruf atau lebih. Digit bisa jadi bagian dari nama binding, catch22 adalah nama yang valid, misalnya, tapi namanya gak boleh dimulai dengan digit. Nama binding boleh berisi tanda dolar ($) atau underscore (_) tapi gak boleh tanda baca atau karakter khusus lainnya.

Kata dengan makna khusus, kaya let, adalah keyword, dan gak boleh dipakai sebagai nama binding. Ada juga sejumlah kata yang “dicadangkan buat dipakai” di versi JavaScript mendatang, yang juga gak bisa dipakai sebagai nama binding. Daftar lengkap keyword dan kata cadangannya agak panjang:

break case catch class const continue debugger default
delete do else enum export extends false finally for
function if implements import interface in instanceof let
new package private protected public return static super
switch this throw true try typeof var void while with yield

Jangan khawatir soal ngapalin daftar ini. Kalau bikin binding ngehasilin syntax error yang gak terduga, cek apakah kamu lagi nyoba mendefinisikan kata cadangan.

Environment

Kumpulan binding dan nilainya yang ada di suatu waktu disebut environment (lingkungan). Waktu program mulai jalan, environment ini gak kosong. Dia selalu berisi binding yang jadi bagian dari standar bahasa, dan kebanyakan waktu, dia juga punya binding yang nyediain cara buat berinteraksi sama sistem di sekitarnya. Misalnya, di browser, ada fungsi buat berinteraksi sama website yang lagi dimuat dan buat baca input mouse dan keyboard.

Fungsi

Banyak nilai yang disediain di environment bawaan punya tipe function (fungsi). Fungsi adalah potongan program yang dibungkus dalam sebuah nilai. Nilai kaya gitu bisa diterapin buat ngejalanin program yang dibungkusnya. Misalnya, di environment browser, binding prompt megang fungsi yang nampilin dialog kecil yang minta input pengguna. Dipakainya kaya gini:

prompt("Enter passcode");

Dialog prompt yang bertuliskan 'enter passcode'

Ngejalanin fungsi disebut invoking, calling (manggil), atau applying (nerapin). Kamu bisa manggil fungsi dengan naruh tanda kurung setelah ekspresi yang ngehasilin nilai fungsi. Biasanya kamu langsung pakai nama binding yang megang fungsinya. Nilai-nilai di antara tanda kurung dikasih ke program di dalam fungsi. Di contoh tadi, fungsi prompt pakai string yang kita kasih sebagai teks yang ditampilin di kotak dialog. Nilai yang dikasih ke fungsi disebut argumen. Fungsi yang berbeda mungkin butuh jumlah atau tipe argumen yang berbeda.

Fungsi prompt gak banyak dipakai di pemrograman web modern, terutama karena kamu gak punya kendali atas tampilan dialog yang dihasilkan, tapi dia bisa berguna di program mainan dan eksperimen.

Fungsi console.log

Di contoh-contoh, saya pakai console.log buat ngeluarin nilai. Kebanyakan sistem JavaScript (termasuk semua browser web modern dan Node.js) nyediain fungsi console.log yang nulisin argumennya ke suatu perangkat output teks. Di browser, outputnya masuk ke konsol JavaScript. Bagian antarmuka browser ini tersembunyi secara default, tapi kebanyakan browser ngebukanya kalau kamu mencet F12 atau, di Mac, command-option-I. Kalau itu gak jalan, cari di menu item bernama Developer Tools atau yang mirip.

Waktu ngejalanin contoh (atau kodemu sendiri) di halaman buku ini, output console.log bakal ditampilin setelah contohnya, bukan di konsol JavaScript browser.

let x = 30;
console.log("the value of x is", x);
// → the value of x is 30

Walaupun nama binding gak boleh berisi karakter titik, console.log punya satu. Ini karena console.log bukan binding sederhana, tapi ekspresi yang ngambil properti log dari nilai yang dipegang binding console. Kita bakal tahu persis apa artinya ini di Bab 4.

Nilai Kembalian (Return Values)

Nampilin kotak dialog atau nulis teks ke layar adalah side effect. Banyak fungsi berguna karena side effect yang mereka hasilkan. Fungsi juga bisa ngehasilin nilai, dan kalau begitu mereka gak perlu punya side effect buat berguna. Misalnya, fungsi Math.max ngambil berapa pun argumen angka dan ngasih balik yang paling besar.

console.log(Math.max(2, 4));
// → 4

Waktu sebuah fungsi ngehasilin nilai, dia dibilang mengembalikan (return) nilai itu. Apa pun yang ngehasilin nilai adalah ekspresi di JavaScript, yang berarti pemanggilan fungsi bisa dipakai di dalam ekspresi yang lebih besar. Di kode berikut, pemanggilan Math.min, yang kebalikan dari Math.max, dipakai sebagai bagian dari ekspresi penjumlahan:

console.log(Math.min(2, 4) + 100);
// → 102

Bab 3 bakal ngejelasin cara nulis fungsimu sendiri.

Alur Kontrol (Control Flow)

Waktu programmu berisi lebih dari satu statement, statement-statement itu dieksekusi seolah mereka sebuah cerita, dari atas ke bawah. Misalnya, program berikut punya dua statement. Yang pertama minta pengguna masukin angka, dan yang kedua, yang dieksekusi setelah yang pertama, nampilin kuadrat dari angka itu:

let theNumber = Number(prompt("Pick a number"));
console.log("Your number is the square root of " +
            theNumber * theNumber);

Fungsi Number ngonversi nilai jadi angka. Kita butuh konversi itu karena hasil prompt adalah nilai string, dan kita mau angka. Ada fungsi serupa bernama String dan Boolean yang ngonversi nilai ke tipe-tipe itu.

Ini representasi skematis yang agak sepele dari alur kontrol garis lurus:

Diagram yang menunjukkan panah lurus

Eksekusi Bersyarat (Conditional Execution)

Gak semua program itu jalan lurus. Kita mungkin, misalnya, mau bikin jalan bercabang di mana program ngambil cabang yang tepat berdasarkan situasi yang ada. Ini disebut eksekusi bersyarat.

Diagram panah yang terbelah dua, lalu bergabung lagi

Eksekusi bersyarat dibikin pakai keyword if di JavaScript. Di kasus sederhana, kita mau sebagian kode dieksekusi kalau, dan hanya kalau, kondisi tertentu terpenuhi. Kita mungkin, misalnya, mau nampilin kuadrat dari input cuma kalau inputnya beneran angka:

let theNumber = Number(prompt("Pick a number"));
if (!Number.isNaN(theNumber)) {
  console.log("Your number is the square root of " +
              theNumber * theNumber);
}

Dengan modifikasi ini, kalau kamu masukin “parrot”, gak ada output yang ditampilin.

Keyword if ngeksekusi atau ngelewatin sebuah statement tergantung nilai dari ekspresi Boolean. Ekspresi penentunya ditulis setelah keyword, di antara tanda kurung, diikuti statement yang mau dieksekusi.

Fungsi Number.isNaN adalah fungsi standar JavaScript yang ngembaliin true cuma kalau argumen yang dikasih ke dia adalah NaN. Fungsi Number kebetulan ngembaliin NaN kalau kamu ngasih dia string yang gak mewakili angka valid. Jadi, kondisinya diterjemahin jadi “kecuali theNumber itu not-a-number, lakuin ini”.

Statement setelah if dibungkus kurung kurawal ({ dan }) di contoh ini. Kurung kurawal bisa dipakai buat ngelompokin berapa pun statement jadi satu statement, yang disebut block. Kamu juga bisa ngilanginnya di kasus ini, karena dia cuma berisi satu statement, tapi biar gak perlu mikir apakah dia dibutuhin, kebanyakan programmer JavaScript pakai dia di setiap statement yang dibungkus kaya gini. Kita bakal kebanyakan ngikutin konvensi itu di buku ini, kecuali buat one-liner sesekali.

if (1 + 1 == 2) console.log("It's true");
// → It's true

Kamu sering bukan cuma punya kode yang dieksekusi waktu kondisi terpenuhi, tapi juga kode yang nanganin kasus lainnya. Jalur alternatif ini diwakili panah kedua di diagram. Kamu bisa pakai keyword else, bareng if, buat bikin dua jalur eksekusi alternatif yang terpisah:

let theNumber = Number(prompt("Pick a number"));
if (!Number.isNaN(theNumber)) {
  console.log("Your number is the square root of " +
              theNumber * theNumber);
} else {
  console.log("Hey. Why didn't you give me a number?");
}

Kalau kamu punya lebih dari dua jalur buat dipilih, kamu bisa “ngerantai” beberapa pasangan if/else. Ini contohnya:

let num = Number(prompt("Pick a number"));
 
if (num < 10) {
  console.log("Small");
} else if (num < 100) {
  console.log("Medium");
} else {
  console.log("Large");
}

Program bakal ngecek dulu apakah num kurang dari 10. Kalau iya, dia milih cabang itu, nampilin "Small", dan selesai. Kalau gak, dia ngambil cabang else, yang sendiri berisi if kedua. Kalau kondisi kedua (< 100) terpenuhi, itu berarti angkanya minimal 10 tapi di bawah 100, dan "Medium" ditampilin. Kalau gak, cabang else kedua dan terakhir dipilih.

Skema buat program ini kurang lebih kaya gini:

Diagram panah yang terbelah dua, salah satu cabangnya terbelah lagi, sebelum semua cabang bergabung lagi

Loop while dan do

Bayangin program yang ngeluarin semua angka genap dari 0 sampai 12. Salah satu cara nulisnya kaya gini:

console.log(0);
console.log(2);
console.log(4);
console.log(6);
console.log(8);
console.log(10);
console.log(12);

Itu jalan, tapi ide nulis program adalah bikin sesuatu jadi lebih sedikit kerjaan, bukan lebih banyak. Kalau kita butuh semua angka genap di bawah 1.000, pendekatan ini gak bakal bisa dipakai. Yang kita butuhin adalah cara buat ngejalanin sepotong kode berkali-kali. Bentuk alur kontrol ini disebut loop (perulangan).

Diagram panah ke sebuah titik yang punya panah melingkar balik ke dirinya sendiri dan panah lain yang lanjut

Alur kontrol perulangan bikin kita bisa balik ke suatu titik di program tempat kita berada sebelumnya dan ngulanginnya dengan keadaan program kita saat ini. Kalau kita gabungin ini sama binding yang ngitung, kita bisa ngelakuin sesuatu kaya gini:

let number = 0;
while (number <= 12) {
  console.log(number);
  number = number + 2;
}
// → 0
// → 2
//   … dan seterusnya

Statement yang dimulai dengan keyword while bikin sebuah loop. Kata while diikuti ekspresi dalam tanda kurung lalu sebuah statement, mirip banget sama if. Loop terus masuk ke statement itu selama ekspresinya ngehasilin nilai yang jadi true kalau dikonversi ke Boolean.

Binding number nunjukin cara sebuah binding bisa ngelacak kemajuan program. Tiap kali loop ngulang, number dapet nilai yang 2 lebih banyak dari nilai sebelumnya. Di awal tiap pengulangan, dia dibandingin sama angka 12 buat mutusin apakah kerjaan programnya udah selesai.

Sebagai contoh yang beneran ngelakuin sesuatu yang berguna, kita sekarang bisa nulis program yang ngitung dan nampilin nilai 2^10 (2 pangkat 10). Kita pakai dua binding: satu buat ngelacak hasil kita dan satu buat ngitung seberapa sering kita udah ngaliin hasil ini dengan 2. Loop-nya ngetes apakah binding kedua udah nyampe 10 dan, kalau belum, ngupdate kedua binding.

let result = 1;
let counter = 0;
while (counter < 10) {
  result = result * 2;
  counter = counter + 1;
}
console.log(result);
// → 1024

Counter-nya juga bisa aja dimulai dari 1 dan ngecek <= 10, tapi karena alasan yang bakal jelas di Bab 4, ada baiknya terbiasa ngitung dari 0.

Catatan, JavaScript juga punya operator buat pemangkatan (2 ** 10), yang bakal kamu pakai buat ngitung ini di kode beneran, tapi itu bakal ngerusak contohnya.

Loop do adalah struktur kontrol yang mirip loop while. Bedanya cuma di satu hal: loop do selalu ngeksekusi badannya minimal sekali, dan dia baru mulai ngetes apakah harus berhenti setelah eksekusi pertama itu. Buat nyerminin ini, tesnya muncul setelah badan loop:

let yourName;
do {
  yourName = prompt("Who are you?");
} while (!yourName);
console.log("Hello " + yourName);

Program ini bakal maksa kamu masukin nama. Dia bakal nanya lagi dan lagi sampai dapet sesuatu yang bukan string kosong. Nerapin operator ! bakal ngonversi nilai ke tipe Boolean sebelum negasinya, dan semua string kecuali "" dikonversi jadi true. Ini berarti loop terus muter sampai kamu ngasih nama yang gak kosong.

Indentasi Kode

Di contoh-contoh, saya udah nambahin spasi di depan statement yang jadi bagian dari statement yang lebih besar. Spasi ini gak wajib, komputer bakal nerima programnya dengan baik tanpa itu. Bahkan, pergantian baris di program pun opsional. Kamu bisa nulis program sebagai satu baris panjang kalau kamu mau.

Peran indentasi di dalam block ini adalah bikin struktur kode menonjol buat pembaca manusia. Di kode di mana block baru dibuka di dalam block lain, bisa jadi susah ngelihat di mana satu block berakhir dan yang lain dimulai. Dengan indentasi yang benar, bentuk visual program sesuai dengan bentuk block di dalamnya. Saya suka pakai dua spasi buat setiap block yang dibuka, tapi selera beda-beda, ada yang pakai empat spasi, dan ada yang pakai karakter tab. Yang penting adalah setiap block baru nambahin jumlah spasi yang sama.

if (false != true) {
  console.log("That makes sense.");
  if (1 < 2) {
    console.log("No surprise there.");
  }
}

Kebanyakan program editor kode (termasuk yang ada di buku ini) bakal ngebantu dengan otomatis ngasih indentasi baris baru sebesar yang seharusnya.

Loop for

Banyak loop ngikutin pola yang ditunjukin di contoh while. Pertama binding “counter” dibikin buat ngelacak kemajuan loop. Lalu ada loop while, biasanya dengan ekspresi tes yang ngecek apakah counter udah nyampe nilai akhirnya. Di akhir badan loop, counter diupdate buat ngelacak kemajuan.

Karena pola ini sangat umum, JavaScript dan bahasa-bahasa serupa nyediain bentuk yang sedikit lebih pendek dan lebih komprehensif, loop for:

for (let number = 0; number <= 12; number = number + 2) {
  console.log(number);
}
// → 0
// → 2
//   … dan seterusnya

Program ini persis setara dengan contoh nyetak angka genap sebelumnya. Satu-satunya perubahan adalah semua statement yang berhubungan sama “keadaan” loop dikelompokin bareng setelah for.

Tanda kurung setelah keyword for harus berisi dua titik koma. Bagian sebelum titik koma pertama menginisialisasi loop, biasanya dengan mendefinisikan binding. Bagian kedua adalah ekspresi yang ngecek apakah loop harus lanjut. Bagian terakhir ngupdate keadaan loop setelah setiap iterasi. Di kebanyakan kasus, ini lebih pendek dan lebih jelas daripada konstruksi while.

Ini kode yang ngitung 2^10 pakai for bukannya while:

let result = 1;
for (let counter = 0; counter < 10; counter = counter + 1) {
  result = result * 2;
}
console.log(result);
// → 1024

Keluar dari Loop

Bikin kondisi loop ngehasilin false bukan satu-satunya cara loop bisa selesai. Statement break punya efek langsung lompat keluar dari loop yang ngelingkupinya. Penggunaannya ditunjukin di program berikut, yang nyari angka pertama yang lebih besar atau sama dengan 20 dan habis dibagi 7:

for (let current = 20; ; current = current + 1) {
  if (current % 7 == 0) {
    console.log(current);
    break;
  }
}
// → 21

Pakai operator sisa bagi (%) adalah cara gampang buat ngetes apakah sebuah angka habis dibagi angka lain. Kalau iya, sisa pembagiannya nol.

Konstruksi for di contoh ini gak punya bagian yang ngecek akhir loop. Ini berarti loop-nya gak bakal pernah berhenti kecuali statement break di dalamnya dieksekusi.

Kalau kamu ngehapus statement break itu atau gak sengaja nulis kondisi akhir yang selalu ngehasilin true, programmu bakal nyangkut di infinite loop (perulangan tak terbatas). Program yang nyangkut di infinite loop gak bakal pernah selesai jalan, yang biasanya hal buruk.

Kalau kamu bikin infinite loop di salah satu contoh di halaman-halaman ini, biasanya kamu bakal ditanya apakah mau ngehentiin script setelah beberapa detik. Kalau itu gagal, kamu harus nutup tab yang lagi kamu pakai buat pulih.

Keyword continue mirip break dalam hal dia ngaruh ke kemajuan loop. Waktu continue ditemuin di badan loop, kontrol lompat keluar dari badan dan lanjut ke iterasi berikutnya dari loop.

Ngupdate Binding dengan Ringkas

Terutama waktu looping, program sering perlu “ngupdate” binding buat megang nilai berdasarkan nilai sebelumnya dari binding itu.

counter = counter + 1;

JavaScript nyediain jalan pintas buat ini:

counter += 1;

Jalan pintas serupa jalan buat banyak operator lain, kaya result *= 2 buat ngegandain result atau counter -= 1 buat ngitung mundur.

Ini bikin kita bisa lebih memperpendek contoh ngitung kita:

for (let number = 0; number <= 12; number += 2) {
  console.log(number);
}

Buat counter += 1 dan counter -= 1, ada padanan yang lebih pendek lagi: counter++ dan counter--.

Dispatch Berdasarkan Nilai dengan switch

Gak jarang kode keliatan kaya gini:

if (x == "value1") action1();
else if (x == "value2") action2();
else if (x == "value3") action3();
else defaultAction();

Ada konstruksi bernama switch yang dimaksudkan buat nyatain “dispatch” kaya gitu dengan cara yang lebih langsung. Sayangnya, sintaks yang dipakai JavaScript buat ini (yang dia warisin dari keluarga bahasa pemrograman C/Java) agak canggung, rantai statement if mungkin keliatan lebih bagus. Ini contohnya:

switch (prompt("What is the weather like?")) {
  case "rainy":
    console.log("Remember to bring an umbrella.");
    break;
  case "sunny":
    console.log("Dress lightly.");
  case "cloudy":
    console.log("Go outside.");
    break;
  default:
    console.log("Unknown weather type!");
    break;
}

Kamu boleh naruh berapa pun label case di dalam block yang dibuka switch. Program bakal mulai ngeksekusi di label yang sesuai dengan nilai yang dikasih ke switch, atau di default kalau gak ada nilai yang cocok. Dia bakal terus ngeksekusi, bahkan melewati label lain, sampai nyampe statement break. Di beberapa kasus, kaya kasus "sunny" di contoh, ini bisa dipakai buat berbagi kode antar kasus (dia nyaranin keluar rumah buat cuaca cerah maupun berawan). Tapi hati-hati, gampang banget lupa break kaya gitu, yang bakal bikin program ngeksekusi kode yang gak kamu mau dieksekusi.

Kapitalisasi

Nama binding gak boleh berisi spasi, tapi sering kali berguna pakai beberapa kata buat ngejelasin dengan jelas apa yang diwakili bindingnya. Ini kurang lebih pilihanmu buat nulis nama binding dengan beberapa kata di dalamnya:

fuzzylittleturtle
fuzzy_little_turtle
FuzzyLittleTurtle
fuzzyLittleTurtle

Gaya pertama bisa susah dibaca. Saya lumayan suka tampilan underscore-nya, walaupun gaya itu agak menyakitkan buat diketik. Fungsi-fungsi standar JavaScript, dan kebanyakan programmer JavaScript, ngikutin gaya terakhir, mereka ngapitalisasi setiap kata kecuali yang pertama. Gak susah buat terbiasa sama hal-hal kecil kaya gitu, dan kode dengan gaya penamaan campur bisa gak enak dibaca, jadi kita ngikutin konvensi ini.

Di beberapa kasus, kaya fungsi Number, huruf pertama binding juga dikapitalisasi. Ini dilakuin buat nandain fungsi ini sebagai constructor. Bakal jelas apa itu constructor di Bab 6. Buat sekarang, yang penting adalah gak terganggu sama ketidakkonsistenan yang keliatan ini.

Komentar

Sering kali, kode mentah gak nyampein semua informasi yang kamu mau program sampein ke pembaca manusia, atau dia nyampeinnya dengan cara yang begitu samar sampai orang mungkin gak paham. Di waktu lain, kamu mungkin cuma mau nyertain beberapa pemikiran terkait sebagai bagian dari programmu. Buat inilah komentar ada.

Komentar adalah potongan teks yang jadi bagian dari program tapi sepenuhnya diabaikan komputer. JavaScript punya dua cara nulis komentar. Buat nulis komentar satu baris, kamu bisa pakai dua karakter garis miring (//) lalu teks komentarnya setelah itu:

let accountBalance = calculateBalance(account);
// It's a green hollow where a river sings
accountBalance.adjust();
// Madly catching white tatters in the grass.
let report = new Report();
// Where the sun on the proud mountain rings:
addToReport(accountBalance, report);
// It's a little valley, foaming like light in a glass.

Komentar // cuma berlaku sampai akhir baris. Bagian teks di antara /* dan */ bakal diabaikan seluruhnya, terlepas dari apakah dia berisi pergantian baris. Ini berguna buat nambahin blok informasi soal sebuah file atau potongan program:

/*
  I first found this number scrawled on the back of an old
  notebook. Since then, it has often dropped by, showing up in
  phone numbers and the serial numbers of products that I've
  bought. It obviously likes me, so I've decided to keep it.
*/
const myNumber = 11213;

Ringkasan

Sekarang kamu tahu bahwa program dibangun dari statement, yang sendirinya kadang berisi statement lagi. Statement cenderung berisi ekspresi, yang sendirinya bisa dibangun dari ekspresi yang lebih kecil.

Naruh statement satu setelah yang lain ngasih kamu program yang dieksekusi dari atas ke bawah. Kamu bisa ngenalin gangguan di alur kontrol pakai statement bersyarat (if, else, dan switch) dan perulangan (while, do, dan for).

Binding bisa dipakai buat nyimpen potongan data di bawah sebuah nama, dan mereka berguna buat ngelacak keadaan di programmu. Environment adalah kumpulan binding yang udah didefinisikan. Sistem JavaScript selalu naruh sejumlah binding standar yang berguna ke environment-mu.

Fungsi adalah nilai spesial yang ngebungkus potongan program. Kamu bisa manggilnya dengan nulis namaFungsi(argumen1, argumen2). Pemanggilan fungsi kaya gitu adalah ekspresi dan bisa ngehasilin nilai.

Poin-poin pentingnya:

  1. Ekspresi ngehasilin nilai; statement adalah kalimat utuh yang harus punya side effect biar berguna. Selalu pakai titik koma.
  2. Binding (let, const, var) itu tentakel yang menggenggam nilai, bukan kotak. const gak bisa ditunjuk ulang.
  3. Alur kontrol: if/else buat bercabang, while/do/for buat ngulang, break buat keluar, continue buat lompat ke iterasi berikutnya, switch buat dispatch (hati-hati lupa break).
  4. Jalan pintas update: +=, -=, *=, ++, --.
  5. Konvensi nama: camelCase, huruf besar di awal cuma buat constructor kaya Number.
  6. Komentar: // satu baris, /* ... */ banyak baris.

Latihan

Kalau kamu gak yakin gimana cara ngetes solusi latihanmu, lihat pengenalan.

Setiap latihan dimulai dengan deskripsi masalah. Baca deskripsi ini dan coba selesaikan latihannya. Kalau kamu nemu masalah, pertimbangkan buat baca petunjuk setelah latihannya. Kamu bisa nemuin solusi lengkap latihan secara online di https://eloquentjavascript.net/code (di catatan ini, solusinya udah saya tempelin di bagian paling bawah tiap latihan). Kalau kamu mau belajar sesuatu dari latihannya, saya nyaranin lihat solusinya cuma setelah kamu udah nyelesaiin latihannya, atau setidaknya setelah kamu udah nyerang dia cukup lama dan keras sampai sedikit pusing.

Ngeloop Segitiga

Tulis loop yang bikin tujuh pemanggilan console.log buat ngeluarin segitiga berikut:

#
##
###
####
#####
######
#######

Mungkin berguna buat tahu bahwa kamu bisa nemuin panjang string dengan nulis .length setelahnya.

let abc = "abc";
console.log(abc.length);
// → 3

Kebanyakan latihan berisi potongan kode yang bisa kamu modifikasi buat nyelesaiin latihannya. Ingat kamu bisa ngeklik blok kode buat ngeditnya (di website aslinya).

// Kodemu di sini.

Petunjuk:

Kamu bisa mulai dengan program yang nyetak angka 1 sampai 7, yang bisa kamu turunin dengan bikin beberapa modifikasi ke contoh nyetak angka genap yang dikasih sebelumnya di bab ini, waktu loop for diperkenalkan.

Sekarang pertimbangkan kesetaraan antara angka dan string karakter pagar. Kamu bisa pergi dari 1 ke 2 dengan nambahin 1 (+= 1). Kamu bisa pergi dari "#" ke "##" dengan nambahin karakter (+= "#"). Jadi, solusimu bisa ngikutin program nyetak angka dengan dekat.

Solusi:

for (let line = "#"; line.length < 8; line += "#")
  console.log(line);

FizzBuzz

Tulis program yang pakai console.log buat nyetak semua angka dari 1 sampai 100, dengan dua pengecualian. Buat angka yang habis dibagi 3, cetak "Fizz" bukannya angkanya, dan buat angka yang habis dibagi 5 (dan bukan 3), cetak "Buzz" sebagai gantinya.

Kalau itu udah jalan, modifikasi programmu buat nyetak "FizzBuzz" buat angka yang habis dibagi 3 dan 5 sekaligus (dan tetap nyetak "Fizz" atau "Buzz" buat angka yang cuma habis dibagi salah satunya).

(Ini sebenernya pertanyaan wawancara yang diklaim bisa nyaring persentase signifikan kandidat programmer. Jadi kalau kamu bisa nyelesaiinnya, nilai pasar kerjamu baru aja naik.)

// Kodemu di sini.

Petunjuk:

Ngelewatin angka-angka jelas kerjaan loop, dan milih apa yang dicetak adalah soal eksekusi bersyarat. Ingat trik pakai operator sisa bagi (%) buat ngecek apakah sebuah angka habis dibagi angka lain (punya sisa nol).

Di versi pertama, ada tiga kemungkinan hasil buat setiap angka, jadi kamu harus bikin rantai if/else if/else.

Versi kedua program punya solusi yang lugas dan yang cerdik. Solusi sederhananya adalah nambahin “cabang” bersyarat lain buat ngetes kondisi yang dikasih secara persis. Buat solusi cerdiknya, bangun string yang berisi kata atau kata-kata yang mau dikeluarin dan cetak kata ini atau angkanya kalau gak ada kata, mungkin dengan memanfaatkan operator || dengan baik.

Solusi:

for (let n = 1; n <= 100; n++) {
  let output = "";
  if (n % 3 == 0) output += "Fizz";
  if (n % 5 == 0) output += "Buzz";
  console.log(output || n);
}

Papan Catur

Tulis program yang bikin string yang mewakili grid 8×8, pakai karakter newline buat misahin baris. Di setiap posisi grid ada spasi atau karakter ”#”. Karakter-karakternya harus membentuk papan catur.

Ngasih string ini ke console.log seharusnya nampilin sesuatu kaya gini:

 # # # #
# # # # 
 # # # #
# # # # 
 # # # #
# # # # 
 # # # #
# # # # 

Kalau kamu udah punya program yang ngehasilin pola ini, definisikan binding size = 8 dan ubah programnya biar jalan buat size berapa pun, ngeluarin grid dengan lebar dan tinggi yang dikasih.

// Kodemu di sini.

Petunjuk:

Kamu bisa ngebangun stringnya dengan mulai dari string kosong ("") dan berulang kali nambahin karakter. Karakter newline ditulis "\n".

Buat kerja dengan dua dimensi, kamu bakal butuh loop di dalam loop. Kasih kurung kurawal di badan kedua loop biar gampang ngelihat di mana mereka mulai dan berakhir. Coba kasih indentasi yang benar ke badan-badan ini. Urutan loop-nya harus ngikutin urutan kita ngebangun stringnya (baris per baris, kiri ke kanan, atas ke bawah). Jadi loop luar nanganin baris, dan loop dalam nanganin karakter di satu baris.

Kamu bakal butuh dua binding buat ngelacak kemajuanmu. Buat tahu apakah harus naruh spasi atau tanda pagar di posisi tertentu, kamu bisa ngetes apakah jumlah kedua counter-nya genap (% 2).

Ngakhirin baris dengan nambahin karakter newline harus terjadi setelah barisnya selesai dibangun, jadi lakuin ini setelah loop dalam tapi di dalam loop luar.

Solusi:

let size = 8;
 
let board = "";
 
for (let y = 0; y < size; y++) {
  for (let x = 0; x < size; x++) {
    if ((x + y) % 2 == 0) {
      board += " ";
    } else {
      board += "#";
    }
  }
  board += "\n";
}
 
console.log(board);