Dari masa sekolah kita sudah tahu: 2 + 3 * 4 bernilai 14, bukan 20, karena perkalian dihitung sebelum penjumlahan. Engine JavaScript memegang aturan urutan yang sama — ditambah banyak aturan lain untuk operator non-matematika. Kesalahan menebak urutan ini berbahaya secara senyap: program tetap berjalan, tidak ada pesan error, tetapi hasilnya meleset dari maksud kita.

Chapter ini merangkum urutan prioritas (operator precedence) utama, membuktikannya dengan ekspresi campur, membahas arah evaluasi untuk operator setara, dan menutup dengan satu kasus khusus yang memang ditolak engine: memadukan ?? dengan || atau && tanpa tanda kurung.

Tabel Urutan Prioritas #

Daftar berikut disusun dari yang paling diutamakan (dihitung lebih dulu) hingga yang paling akhir:

UrutanOperatorContoh
1() tanda kurung(2 + 3) * 4
2** pangkat2 ** 10
3Unary: -x, !x-angka, !aktif
4* / %total % 3
5+ -a + b
6< <= > >=nilai >= batas
7== === != !==nilai === 1
8&&lulus && aktif
9||kupon || poin
10??input ?? 0
11?: ternarystok > 0 ? "ada" : "habis"
12= += -= dst.stok += 5

Cara membacanya: operator pada urutan lebih atas mengikat operand-nya lebih kuat. Baris 6–7 memuat dua kelompok perbandingan; keduanya berada di bawah aritmatika (sehingga 3 + 4 > 5 dibaca (3 + 4) > 5) dan di atas operator logika (sehingga hasil perbandingan langsung menjadi operand &&).

Membuktikan Urutan dengan Ekspresi Campur #

Berkas berikut menguji enam ekspresi yang masing-masing menyentuh bagian tabel berbeda. Tebak dulu hasilnya, lalu bandingkan dengan keluaran:

// urutan-hitung.js
// Membuktikan urutan evaluasi operator dengan ekspresi campur.

// Perkalian dievaluasi sebelum penjumlahan.
console.log(2 + 3 * 4);

// Tanda kurung mengubah urutan evaluasi.
console.log((2 + 3) * 4);

// Pengurangan dievaluasi kiri ke kanan.
console.log(10 - 4 - 3);

// Pangkat dievaluasi kanan ke kiri.
console.log(2 ** 3 ** 2);

// Modulo dan perbandingan bergabung dengan operator logika.
console.log(3 + 4 > 5 && 10 % 3 === 1);

// ?? dipadukan dengan || setelah diberi tanda kurung.
const inputPengguna = null;
console.log((inputPengguna ?? 0) || "belum ada");

Output yang Dihasilkan:

text
14
20
3
512
true
belum ada

Mari kita telaah baris-baris pentingnya:

  1. Baris 5 (console.log(2 + 3 * 4);): * berada di atas + pada tabel, sehingga 3 * 4 dihitung lebih dulu menjadi 12, lalu 2 + 12 menghasilkan 14.
  2. Baris 8 (console.log((2 + 3) * 4);): tanda kurung memaksa urutan evaluasi lain — 2 + 3 menjadi 5, lalu 5 * 4 menghasilkan 20. Tanda kurung berada di urutan tertinggi dan selalu bisa kita pakai untuk menegaskan maksud.
  3. Baris 11 (console.log(10 - 4 - 3);): kedua operator setara, sehingga aturan pemasangan (associativity) yang menentukan. Pengurangan dipasang kiri-ke-kanan: (10 - 4) - 3 menghasilkan 3, bukan 10 - (4 - 3) yang bernilai 9.
  4. Baris 14 (console.log(2 ** 3 ** 2);): operator ** adalah pengecualian — ia dipasang kanan-ke-kiri. Ekspresi itu dibaca 2 ** (3 ** 2) = 2 ** 9 = 512, bukan (2 ** 3) ** 2 = 64.
  5. Baris 17 (console.log(3 + 4 > 5 && 10 % 3 === 1);): ekspresi paling padat di berkas ini. Urutan kerja engine: 3 + 4 menjadi 7; % lebih tinggi dari ===, sehingga 10 % 3 menjadi 1 lalu dibandingkan dengan === 1; kini ekspresinya tinggal 7 > 5 && true === true, dan hasil akhirnya true.
  6. Baris 21 (console.log((inputPengguna ?? 0) || "belum ada");): ?? berada di bawah ||, sehingga tanpa kurung gabungan ini memang ditolak engine. Dengan kurung, inputPengguna ?? 0 dievaluasi dulu menjadi 0, lalu 0 || "belum ada" menghasilkan "belum ada".

Unary Minus Bertemu Pangkat #

Dua operator pada tabel di atas punya hubungan istimewa: unary minus dan pangkat. Ketika keduanya bertemu langsung tanpa tanda kurung — seperti console.log(-2 ** 2); — engine menolak programnya sebelum eksekusi dengan pesan:

text
SyntaxError: Unary operator used immediately before exponentiation expression. Parenthesis must be used to disambiguate operator precedence

Ekspresi -2 ** 2 bisa dibaca dua cara — “negasi dari 2 ** 2” (hasilnya -4) atau “dua negatif dipangkatkan dua” (hasilnya 4) — dan keduanya berbeda. Seperti pada kasus ?? berikutnya, engine menuntut kejelasan lewat tanda kurung:

js
console.log((-2) ** 2);
console.log(-(2 ** 2));

Output yang Dihasilkan:

text
4
-4

Kedua bentuk kini sah dan berbeda hasilnya sesuai posisi kurungnya: (-2) ** 2 memangkatkan dua negatif menjadi 4, sedangkan -(2 ** 2) memangkatkan dua dahulu lalu menegasi hasilnya menjadi -4.

Ketika ?? Dipadukan Tanpa Tanda Kurung #

Aturan poin 6 di atas bersifat mutlak: ?? tidak boleh bersebelahan langsung dengan || atau &&. Berkas berikut sengaja melanggarnya:

// gabungan-tanpa-kurung.js
// Demonstrasi: ?? tidak boleh dipadukan langsung dengan || tanpa tanda kurung.

const nilaiA = null;
const nilaiB = 0;

const hasil = nilaiA ?? nilaiB || "cadangan";

console.log(hasil);

Jika dijalankan, program tidak pernah sampai ke tahap eksekusi. Node berhenti saat membaca sintaks dan menampilkan pesan berikut (inti transkripnya):

text
const hasil = nilaiA ?? nilaiB || "cadangan";
                               ^^

SyntaxError: Unexpected token '||'

Tanda ^^ pada transkrip menunjuk langsung ke || — engine tidak mau menebak maksud kita: apakah yang dimaksud (nilaiA ?? nilaiB) || "cadangan" atau nilaiA ?? (nilaiB || "cadangan")? Kedua pembacaan itu menghasilkan nilai berbeda (0 versus "cadangan"), dan alih-alih memilih salah satu secara senyap, spesifikasi JavaScript memaksa penulisnya menyatakan maksud lewat tanda kurung. Padanan dengan && diperlakukan sama: a ?? b && c juga ditolak dengan SyntaxError: Unexpected token '&&'.

Dengan urutan evaluasi ini kita sudah tahu persis bagaimana engine membaca satu baris kode. Satu area berbahaya tersisa yang menyangkut aturan antartipe: operator kesetaraan == dan === beserta konversi tipe senyapnya — topik penutup section ini, chapter Equality dan Type Coercion.

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

gabungan-tanpa-kurung.js

Unduh berkas
javascript
// gabungan-tanpa-kurung.js
// Demonstrasi: ?? tidak boleh dipadukan langsung dengan || tanpa tanda kurung.

const nilaiA = null;
const nilaiB = 0;

const hasil = nilaiA ?? nilaiB || "cadangan";

console.log(hasil);

urutan-hitung.js

Unduh berkas
javascript
// urutan-hitung.js
// Membuktikan urutan evaluasi operator dengan ekspresi campur.

// Perkalian dievaluasi sebelum penjumlahan.
console.log(2 + 3 * 4);

// Tanda kurung mengubah urutan evaluasi.
console.log((2 + 3) * 4);

// Pengurangan dievaluasi kiri ke kanan.
console.log(10 - 4 - 3);

// Pangkat dievaluasi kanan ke kiri.
console.log(2 ** 3 ** 2);

// Modulo dan perbandingan bergabung dengan operator logika.
console.log(3 + 4 > 5 && 10 % 3 === 1);

// ?? dipadukan dengan || setelah diberi tanda kurung.
const inputPengguna = null;
console.log((inputPengguna ?? 0) || "belum ada");