Nilai, Tipe, dan Operator

BAB 5: Ekspresi dan Statement

Perbedaan ekspresi dan statement, serta bagaimana JavaScript mengeksekusi kode baris demi baris.

Di bab sebelumnya, kita membahas operator — simbol-simbol yang mengolah nilai. Tapi ada pertanyaan yang lebih mendasar: dari semua potongan kode yang kamu tulis, apa sebenarnya yang sedang terjadi di sana? Baris mana yang menghasilkan nilai, dan baris mana yang menjalankan aksi? Dua kategori ini punya nama: ekspresi dan statement. Memahami perbedaannya akan membuat kamu lebih sadar dalam membaca dan menulis kode.

Ekspresi: Kode yang Menghasilkan Nilai

Ekspresi adalah potongan kode yang, ketika dievaluasi JavaScript, menghasilkan sebuah nilai. Setiap ekspresi bisa kamu bayangkan sebagai sesuatu yang bisa dimasukkan ke dalam kotak dan diberikan ke bagian lain dari program.

JavaScriptJAVASCRIPT
// ekspresi.js
42              // menghasilkan: 42
"halo"          // menghasilkan: "halo"
3 + 4           // menghasilkan: 7
true && false   // menghasilkan: false
typeof "teks"   // menghasilkan: "string"

Setiap baris di atas adalah ekspresi karena semuanya menghasilkan nilai. Kamu bisa menggunakan ekspresi di mana pun JavaScript mengharapkan nilai — dalam assignment, sebagai argumen fungsi, atau sebagai bagian dari ekspresi yang lebih besar.

JavaScriptJAVASCRIPT
// ekspresi.js
let harga = 50000;                    // ekspresi "50000" diassign ke harga
let diskon = harga * 0.1;             // ekspresi "harga * 0.1" menghasilkan 5000
console.log(diskon > 1000 ? "OK" : "Kecil"); // ekspresi ternary sebagai argumen

Ekspresi bisa digabungkan menjadi ekspresi yang lebih besar: harga * 0.1 terdiri dari tiga ekspresi — harga, 0.1, dan operator * yang menggabungkan keduanya menjadi satu ekspresi baru.

Statement: Kode yang Menjalankan Aksi

Statement adalah instruksi lengkap yang meminta JavaScript melakukan sesuatu. Berbeda dari ekspresi, statement tidak menghasilkan nilai yang bisa langsung dipakai di konteks lain — ia hanya melakukan sesuatu.

JavaScriptJAVASCRIPT
// statement.js
if (true) {
  console.log("ini dijalankan");
}

for (let i = 0; i < 3; i++) {
  console.log(i);
}

while (false) {
  // tidak pernah dijalankan
}

Kamu tidak bisa memasukkan if, for, atau while ke dalam ekspresi:

JavaScriptJAVASCRIPT
// TIDAK VALID
let x = if (true) { 1 } else { 2 };   // SyntaxError
let y = for (let i = 0; i < 3; i++) { i }; // SyntaxError

Aturannya sederhana: statement tidak bisa dipakai di posisi yang memerlukan nilai.

Expression Statement

Ada kategori khusus yang menjadi jembatan antara keduanya: expression statement. Ini adalah ekspresi yang dipakai sebagai statement — ekspresi berdiri sendiri dalam satu baris, tapi nilainya dibuang.

JavaScriptJAVASCRIPT
// expression-statement.js
console.log("halo");  // pemanggilan fungsi — nilai return dibuang
i++;                  // increment — hasil ekspresi dibuang
stok = 100;           // assignment — nilai "100" dibuang setelah disimpan

Tiga baris di atas adalah ekspresi (ketiganya menghasilkan nilai), tapi digunakan sebagai statement. Nilainya tidak disimpan ke mana-mana — yang penting adalah efek sampingnya (side effect): mencetak ke console, mengubah nilai i, atau menyimpan nilai ke stok.

Expression statement bermakna hanya jika memiliki side effect. Menulis 3 + 4; sebagai expression statement adalah kode yang valid tapi tidak berguna — nilai 7 dihitung lalu dibuang begitu saja.

Declarations

Ada satu kategori lagi yang perlu dibedakan: declaration. Declaration mengikat sebuah nama ke nilai atau ke fungsi.

JavaScriptJAVASCRIPT
// declaration.js
let nama = "Budi";
const TARIF = 0.11;
function sapa(nama) {
  return `Halo, ${nama}!`;
}
class Pengguna {
  constructor(nama) {
    this.nama = nama;
  }
}

let dan const bersifat lexical declaration — lebih ketat dari var. Ini penting karena ada konteks tertentu di mana var boleh dipakai tapi let/const tidak:

JavaScriptJAVASCRIPT
// var boleh tanpa block
if (true)
  var x = 10;  // valid

// let/const tidak boleh tanpa block
if (true)
  let y = 10;  // SyntaxError: Lexical declaration cannot appear in single-statement context

Jika kamu menggunakan let atau const di dalam if, for, atau while tanpa kurung kurawal, JavaScript akan melempar error. Solusinya: selalu gunakan kurung kurawal {}.

JavaScriptJAVASCRIPT
if (true) {
  let y = 10;  // valid — dibungkus block statement
}

Ekspresi yang Tidak Boleh Memulai Statement

Ada situasi di mana ekspresi tertentu tidak boleh ditulis di awal baris tanpa "petunjuk" tambahan. Ini karena JavaScript membaca token pertama untuk memutuskan apa yang sedang diuraikan.

Jika baris dimulai dengan function, JavaScript mengira itu adalah function declaration — bukan ekspresi:

JavaScriptJAVASCRIPT
// function-expression.js

// TIDAK VALID — dibaca sebagai declaration, bukan ekspresi
function() { return 42; }();  // SyntaxError

// VALID — kurung di depan memberi tahu JavaScript ini adalah ekspresi
(function() { return 42; })();  // 42

// VALID — pakai arrow function yang tidak ambigu
(() => 42)();  // 42

Begitu juga dengan kurung kurawal {} — jika diletakkan di awal baris, JavaScript akan membaca ini sebagai block statement, bukan object literal:

JavaScriptJAVASCRIPT
// TIDAK VALID — {} dibaca sebagai block kosong, "a: 1" adalah label dan number
{a: 1};  // tidak menghasilkan object

// VALID — bungkus dengan kurung
({a: 1});  // { a: 1 }

Pola ini jarang kamu temui sehari-hari, tapi penting dipahami ketika menulis kode yang menggunakan Immediately Invoked Function Expression (IIFE).

Semicolon dan ASI

Di JavaScript, setiap statement umumnya diakhiri dengan titik koma (;). Tapi JavaScript memiliki fitur yang disebut Automatic Semicolon Insertion (ASI) — ia secara otomatis menyisipkan titik koma di posisi tertentu ketika kamu melupakannya.

JavaScriptJAVASCRIPT
// tanpa-titik-koma.js
let x = 10
let y = 20
console.log(x + y)  // 30 — bekerja karena ASI menyisipkan ; setelah setiap baris

Kode di atas berjalan normal karena ASI menyisipkan titik koma setelah setiap baris. Tapi ASI tidak selalu bekerja seperti yang kamu harapkan. Ada kasus-kasus di mana hasilnya mengejutkan:

JavaScriptJAVASCRIPT
// jebakan-asi.js

// Jebakan 1: baris dimulai dengan tanda kurung
let a = 1
(1).toString()
// JavaScript membacanya sebagai: let a = 1(1).toString()
// Error: 1 is not a function
JavaScriptJAVASCRIPT
// Jebakan 2: baris dimulai dengan kurung siku
let b = 1
[1, 2, 3].forEach(console.log)
// JavaScript membacanya sebagai: let b = 1[1, 2, 3].forEach(console.log)
// TypeError: Cannot read properties of undefined
JavaScriptJAVASCRIPT
// Jebakan 3: return di baris terpisah
function hitung() {
  return
  42;
}
console.log(hitung()); // undefined — bukan 42!
// ASI menyisipkan ; setelah "return", membuat "return;" tanpa nilai

Jebakan return di atas adalah salah satu yang paling sering menyebabkan bug. Selalu letakkan nilai return di baris yang sama dengan keyword return, atau gunakan tanda kurung jika nilainya panjang:

JavaScriptJAVASCRIPT
return (
  kondisi && nilai
);

Kapan Menggunakan Titik Koma

Ada dua kubu di komunitas JavaScript: yang selalu menulis titik koma, dan yang tidak. Keduanya valid — yang penting konsisten.

Jika kamu memilih tidak menulis titik koma, pahami lima token yang bisa "menipu" ASI: (, [, `, /, dan +. Jika baris berikutnya dimulai dengan salah satu dari token ini, ada risiko ASI tidak menyisipkan titik koma di tempat yang kamu harapkan.

Solusi umum untuk kode tanpa titik koma: prefix baris yang berpotensi ambigu dengan ;:

JavaScriptJAVASCRIPT
// aman-tanpa-semicolon.js
let x = 10

;[1, 2, 3].forEach(n => console.log(n + x))  // prefix ; sebagai "pelindung"
;(function() { console.log("IIFE") })()

Cara ini terlihat aneh tapi cukup umum di basis kode yang memilih gaya tanpa titik koma.

Cara JavaScript Membaca Kode

Program JavaScript adalah deretan statement yang dieksekusi dari atas ke bawah. Ketika JavaScript menemukan sebuah statement, ia menjalankannya — dan jika statement itu adalah expression statement, nilai yang dihasilkan ekspresinya dibuang setelah efek sampingnya terjadi.

CodeTEXT
Program JavaScript

  Statement 1 (declaration)
  ↓ dieksekusi
  Statement 2 (expression statement)
  ↓ dieksekusi
  Statement 3 (control flow: if/for/while)
  ↓ dieksekusi (bisa membuat percabangan/perulangan)
  Statement 4 ...
CodeIMAGE
A clean technical diagram showing JavaScript program execution flow. Vertical flowchart with 4 rectangular boxes stacked top to bottom, connected by downward arrows. Box 1 labeled "Deklarasi let/const" in blue. Box 2 labeled "Expression Statement" in green. Box 3 labeled "Control Flow (if/for/while)" in orange with a diamond decision shape branching off to the right showing "percabangan". Box 4 labeled "Statement berikutnya..." in gray. All arrows point downward. White background, flat design, sans-serif font, all labels in Indonesian, 16:9 aspect ratio.

Setiap ekspresi di dalam statement dievaluasi terlebih dahulu, dari dalam ke luar, sebelum statement itu sendiri dieksekusi:

JavaScriptJAVASCRIPT
// urutan-evaluasi.js
let total = (5 + 3) * 2;
//          -----        (1) 5 + 3 = 8
//          ---------    (2) 8 * 2 = 16
// -------               (3) 16 disimpan ke total

Pemahaman ini penting ketika ekspresi memiliki side effect — seperti increment ++ atau pemanggilan fungsi yang mengubah state. Urutan evaluasi menentukan hasilnya.

Latihan

Tiga soal berikut melatih kemampuanmu membedakan ekspresi, statement, dan declaration:

  1. Dari daftar berikut, identifikasi mana ekspresi dan mana statement:

    JavaScriptJAVASCRIPT
    let x = 5;
    x * 2;
    if (x > 3) { console.log(x); }
    x++;
    typeof x;
    for (let i = 0; i < x; i++) { console.log(i); }
    

    Untuk setiap item, jelaskan alasanmu dalam satu kalimat.

  2. Kode berikut memiliki bug yang disebabkan ASI. Temukan dan perbaiki:

    JavaScriptJAVASCRIPT
    function hitungTotal(harga, jumlah) {
      let diskon = 0
      if (jumlah >= 10) {
        diskon = 0.15
      }
      return
        harga * jumlah * (1 - diskon)
    }
    console.log(hitungTotal(50000, 10))
    

    Apa yang sebenarnya dikembalikan oleh fungsi ini? Mengapa?

  3. Tulis ulang if/else berikut menjadi ekspresi ternary, dan jelaskan apakah semua if/else bisa selalu dikonversi ke ternary:

    JavaScriptJAVASCRIPT
    let suhu = 32;
    let kondisi;
    if (suhu > 30) {
      kondisi = "Panas";
    } else if (suhu > 20) {
      kondisi = "Sejuk";
    } else {
      kondisi = "Dingin";
    }
    

Dengan pemahaman ekspresi dan statement, kamu sekarang punya gambaran yang lebih lengkap tentang bagaimana JavaScript "membaca" kode yang kamu tulis. Fondasi ini akan sangat terasa manfaatnya ketika kita masuk ke topik berikutnya — variabel dan binding, di mana cara JavaScript menyimpan dan mengingat nilai akan menjadi pusat perhatian.

Referensi

  1. 1 Statements and declarations - JavaScript Reference | MDN Web Docs
  2. 2 Expression statement - JavaScript Reference | MDN Web Docs
  3. 3 Automatic Semicolon Insertion - Lexical grammar | MDN Web Docs