1 September 2021

Operator dasar, maths

Kita tahu banyak operator dari sekolah. Mereka adalah penambahan +, perkalian *, pengurangan -, dll.

Didalam bagian ini, kita akan memulai dengan menggunakan operator sederhana, lalu kita akan fokus pada aspek khusus Javascript, yang tidak dipelajari pada aritmatika di sekolah.

Istilah: ???unary???, ???binary???, ???operand???

Sebelum kita lanjut, mari pahami dulu terminologi umum.

  • Operand ??? untuk apa operator diaplikasikan. Misalnya, dalam perkalian 5 * 2 ada dua operand: operand kiri 5 dan operand kanan 2. Kadang, orang memanggil ini ???argumen??? ketimbang ???operand???.

  • Operator disebut unary jika ia punya operand tunggal. Misalnya, negasi unary - membalikkan tanda dari angka:

    let x = 1;
    
    x = -x;
    alert( x ); // -1, negasi unary diaplikasikan
  • Operator disebut binary jika ia punya dua operand. Minus yang sama juga berada dalam bentuk binary:

    let x = 1, y = 3;
    alert( y - x ); // 2, minus binary mengurangi nilai

    Formalnya, di contoh di atas kita punya dua operator berbeda yang berbagi simbol yang sama: operator negasi, operator unary yang membalik tanda, dan operator pengurangan, operator biner yang mengurangi angka satu dengan lainnya.

Maths

Operasi matematika dibawah telah didukung didalam Javascript:

  • Penambahan +,
  • Pengurangan -,
  • Perkalian *,
  • Pembagian /,
  • Sisa Bagi %,
  • Eksponensial **.

Keempat operasi pertama sudah cukup jelas, sementara % dan ** membutuhkan lebih banyak kata-kata untuk dijelaskan.

Sisa bagi %

Operator sisa bagi % sebagaimana kelihatannya, tidak berhubungan dengan persen.

Hasil dari a % b adalah nilai sisa dai pembagian antara a oleh b.

Contoh

alert( 5 % 2 ); // 1, sisa dari pembagian antara 5 dibagi 2
alert( 8 % 3 ); // 2, sisa dari pembagian antara 8 dibagi 3

Eksponensial **

Operator eksponensial a ** b mengkalikan a dengan nilai itu sendiri sebanyak b kali.

Dalam matematika sekolah, kita menuliskannya sebagaib.

alert( 2 ** 2 ); // 2?? = 4 alert( 2 ** 3 ); // 2?? = 8 alert( 2 ** 4 ); // 2??? = 16

Sama seperti dalam matematika, operator eksponensial juga didefinisikan untuk bilangan non-bilangan bulat.

Misalnya, akar kuadrat adalah eksponensial dengan :

```js run
alert( 4 ** (1/2) ); // 2 (pangkat 1/2 sama dengan akar kuadrat)
alert( 8 ** (1/3) ); // 2 (pangkat 1/3 sama dengan akar kubik)

Penambahan string dengan +

Ayo kita bertemu dengan fitur dari operator Javascript yang berada diatas aritmatika di sekolah.

Biasanya, operator plus + menambah angka.

Tapi, jika binary + diaplikasikan ke string, ia menggabungkan (konkatenasi) mereka:

let s = "my" + "string";
alert(s); // mystring

Ingat bahwa jika salah satu operand berupa string, maka yang satunya dikonversi ke string juga.

Misalnya:

alert( '1' + 2 ); // "12"
alert( 2 + '1' ); // "21"

Lihat, tak masalah operand manapun yang berupa string. Aturannya simpel: jika salah satu operand adalah string, maka yang satunya dikonversi ke string juga.

Namun, ingat bahwa operasi berjalan dari kiri ke kanan. Jika ada dua angka diikuti string, angka akan ditambah sebelum dikonversi ke string:

Ini adalah contoh yang lebih rumit:

alert(2 + 2 + '1' ); // "41" dan bukan "221"

Disini, operator bekerja secara bergantian. Pertama + menambahkan dua angka, jadi akan menghasilkan 4, lalu selanjutnya + menambahkan string 1 kedalamnya, jadi akan menjadi seperti 4 + '1' = 41.

alert('1' + 2 + 2); // "122" dan bukan "14"

disini, bilangan pertama adalah string, kompiler memperlakukan dua bilangan lainnya sebagai string juga. Bilangan 2 ditambahkan dengan 1, jadi '1' + 2 = "12" dan "12" + 2 = "122".

Operator + hanyalah satu-satunya operator yang mendukung penggunaan string dengan cara semacan itu. Operator aritmatika lainnya hanya bekerja dengan angka dan selalu mengubah operannya menjadi angka.

Ini adalah contoh untuk pengurangan dan pembagian:

alert( 6 - '2' ); // 4, mengubah '2' menjadi angka
alert( '6' / '2' ); // 3, mengubah keduanya menjadi angka

Konversi angka, unary +

Plus + ada dalam dua bentuk: bentuk binary yang kita gunakan di atas dan bentuk unary.

Plus unary atau, dalam kata lain, operator plus + diaplikasikan ke nilai tunggal, tak berefek apapun ke angka. Tapi jika operand bukan angka, plus unary dikonversi ke dalam angka.

Misalnya:

// Tak ada efek ke angka
let x = 1;
alert( +x ); // 1

let y = -2;
alert( +y ); // -2

// Mengkonversi non-angka
alert( +true ); // 1
alert( +"" );   // 0

Sebenarnya ia melakukan hal yang sama seperti Number(...), tapi lebih pendek.

Kebutuhan mengkonversi string ke angka sangat sering meningkat. Misalnya, jika kita memperoleh nilai dari kolom di form HTML, mereka biasanya string. Bagaimana jika kita ingin menjumlahkan mereka?

Plus binary akan menambah mereka sebagai string:

let apples = "2";
let oranges = "3";

alert( apples + oranges ); // "23", plus binary mengkonkatenasi string

Jika kita ingin memperlakukan mereka sebagai angka, kita harus mengkonversi, lalu menjumlahkan mereka:

let apples = "2";
let oranges = "3";

// kedua nilai dikonversi ke angka sebelum plus binary
alert( +apples + +oranges ); // 5

// varian lebih panjang
// alert( Number(apples) + Number(oranges) ); // 5

Dari sisi pandang matematikawan, melimpahnya plus terlihat aneh. Tapi dari sisi pandang programmer, tak ada yang spesial: plus unary diaplikasikan dahulu, lalu mengkonversi string ke angka, dan lalu binary plus menjumlahkan mereka.

Kenapa plus unary diaplikasi ke nilai sebelum binarynya? Seperti yang kita lihat, itu karena peresedensi lebih tinggi mereka.

Presedensi operator

Jika expresi punya lebih dari satu operator, urutan eksekusi ditentukan oleh presedensi mereka, atau dengan kata lain, urutan prioritas default operator.

Dari sekolah, kita semua tahu bahwa perkalian dalam expresi 1 + 2 * 2 harus dihitung sebelum penambahan. Itulah arti dari presedensi. Perkalian disebut memiliki presedensi lebih tinggi dari penambahan.

Tanda kurung mengesampingkan presedensi apapun, jadi jika kita tak puas dengan urutan default, kita bisa gunakan mereka untuk mengubahnya. Misalnya: tulis (1 + 2) * 2.

Ada banyak operator di JavaScript. Tiap operator punya nomor presedensi masing-masing. Nomor yang lebih besar dieksekusi terlebih dahulu. Jika presedensinya sama, urutan eksekusinya dari kiri ke kanan.

Di sini adalah extrak dari tabel presedensi (kamu tak usah mengingat ini, tapi catat bahwa operator unary lebih tinggi dari binary terkait):

Presedensi Nama Tanda
??? ??? ???
17 plus unary +
17 negasi unary -
16 akar pangkat **
15 perkalian *
15 pembagian /
13 penambahan +
13 pengurangan -
??? ??? ???
3 penetapan =
??? ??? ???

Seperti yang kita lihat, ???plus unary??? punya prioritas 17 yang lebih tinggi dari 13 ???penambahan??? (plus binary). Itulah kenapa, dalam expresi "+apples + +oranges", plus unary bekerja sebelum penambahan.

Penetapan

Mari ingat bahwa penetapan = juga merupakan operator. Ia terdaftar di tabel presedensi dengan prioritas sangat rendah 3.

Itulah kenapa, ketika kita tetapkan variabel, seperti x = 2 * 2 + 1, kalkulasinya dilakukan pertama dan kemudian = dievaluasi, menyimpan hasilnya dalam in x.

let x = 2 * 2 + 1;

alert( x ); // 5

Assignment = mengembalikan nilai

Fakta dari = menjadi sebuah operator, bukanlah sebuah hal yang ???fantastis??? konstruksi dari bahasa memiliki implikasi yang menarik.

Kebanyakan operator di Javascript mengembalikan sebuah nilai. Sudah jelas untuk + dan -, tetapi berlaku juga untuk =.

Panggilan x = value menulis value ke dalam x dan mengembalikannya.

Ini adalah demo yang menggunakan penetapan sebagai bagian dari expresi yang rumit:

let a = 1;
let b = 2;

let c = 3 - (a = b + 1);

alert( a ); // 3
alert( c ); // 0

Di contoh di atas, hasil dari expresi (a = b + 1) ialah nilai yang ditetapkan ke a (yaitu 3). Ia kemudian digunakan untuk evaluasi berikutnya.

Kodenya lucu, kan? kita harus mengerti bagaimana itu bekerja, karena terkadang kita melihat hal itu didalam library Javascript.

Dan juga, tolong jangan tulis kode seperti itu. Trik semacam itu tidak akan membuat kode menjadi jelas dan mudah dibaca.

Chaining assignments / Assignments berantai

Fitur menarik lainnya adalah kemampuan untuk melakukan assignments berantai:

let a, b, c;

a = b = c = 2 + 2;

alert( a ); // 4
alert( b ); // 4
alert( c ); // 4

Assignments berantai mengevaluasi dari kanan ke kiri. Pertama, dari ekspresi paling kanan 2 + 2 di evaluasi terlebih dahulu dan dimasukan kedalam variabel disebelah kiri: c, b dan a. Dan diakhir, seluruh variabel saling membagi satu nilai.

Sekali lagi, untuk tujuan kode yang mudak dibaca akan lebih baik untuk membagi kode kedalam beberapa baris:

c = 2 + 2;
b = c;
a = c;

Ini akan mudah untuk dibaca, terutama jika melihatnya secara sekilas.

Mengubah variabel secara langsung

Kita terkadang membutuhkan sebuah operator untuk sebuah variabel dan menyimpan hasil baru didalam variabel yang sama

Contoh:

let n = 2;
n = n + 5;
n = n * 2;

Notasi ini bisa diperpendek dengan menggunakan operator += dan *=:

let n = 2;
n += 5; // sekarang n = 7 (sama dengan n = n + 5)
n *= 2; // sekarang n = 14 (sama dengan n = n * 2)

alert( n ); // 14

Operator dari ???ubah-dan-simpan??? atau bisa disebut mengubah variabel secara langsung hadir pada setiap aritmatik dan operator bitwise: /=, -=, etc.

Operator semacam itu memiliki hak dengan tingkat yang sama dengan assignment yang biasa, jadi mereka akan berjalan setelah kalkulasi lainnya selesai:

let n = 2;

n *= 3 + 5;

alert( n ); // 16  (bagian paling kanan dievaluasi terlebih dahulu, sama seperti n *= 8)

Inkremen/dekremen

Menaikkan atau menurunkan satu angka ialah salah satu operasi numerik paling umum.

Jadi, ada operator spesial untuk itu:

  • Inkremen ++ menaikkan variabel sebanyak 1:

    let counter = 2;
    counter++;        // cara kerjanya sama dengan counter = counter + 1, tapi lebih pendek
    alert( counter ); // 3
- **Decrement** `--` menurunkan variabel sebanyak 1:

    ```js run no-beautify
    let counter = 2;
    counter--;        // cara kerjanya sama dengan counter = counter - 1,tapi lebih pendek
    alert( counter ); // 1
    ```

```warn
Inkremen/dekremen cuma bisa diaplikasikan ke variabel. Mencoba menggunakan itu pada nilai seperti `5++` akan menghasilkan galat.
???```

Operator `++` dan `--` bisa ditaruh sebelum atau setelah variabel.

- Ketika operatornya ditaruh setelah variabel, ia ada dalam "bentuk postfix": `counter++`.
- "Bentuk prefix" ialah ketika operatornya ditaruh sebelum variabel: `++counter`.

Kedua pernyataan ini melakukan hal yang sama: menambah `counter` sebanyak `1`.

Apakah ada perbedaan? Ya, tapi kita cuma bisa melihatnya jika kita menggunakan nilai kembalian `++/--`.

Mari kita klarifikasi. Seperti yang kita tahu, semua operator mengembalikan nilai. Inkremen/dekremen bukan pengecualian. Bentuk prefix mengembalikan nilai baru sedangkan bentuk postfix mengembalikan nilai lama (sebelum inkremen/dekremen).

Untuk melihat perbedaannya, berikut misalnya:

```js run
let counter = 1;
let a = ++counter; // (*)

alert(a); // 2
???```

Dalam baris `(*)`, bentuk *prefix*`++counter` menginkremen `counter` dan mengembalikan nilai baru, `2`. Jadi, `alert` menampilkan `2`.

Sekarang, mari kita gunakan bentuk postfix:

```js run
let counter = 1;
let a = counter++; // (*) ganti ++counter ke counter++

alert(a); // 1
???```

Dalam baris `(*)`, bentuk *postfix* `counter++` juga menginkremen `counter` tapi mengembalikan nilai *lama* (sebelum inkremen). Jadi, `alert` menampilkan `1`.

Ringkasnya:

- Jika hasil dari inkremen/dekremen tak digunakan, tak ada bedanya bentuk mana yang dipakai:

    ```js run
    let counter = 0;
    counter++;
    ++counter;
    alert( counter ); // 2, kedua counter diatas melakukan hal yang serupa.
    ```
- Jika kita ingin menaikkan nilai *dan* langsung memakai hasil dari operator, kita butuh bentuk prefix:

    ```js run
    let counter = 0;
    alert( ++counter ); // 1
    ```
- Jika kita ingin menginkremen suatu nilai tanpa memakai nilai sebelumnya, kita butuh bentuk postfix:

    ```js run
    let counter = 0;
    alert( counter++ ); // 0
    ```

````smart header="Inkremen/dekremen di antara operator lainnya"
Operator `++/--` bisa juga digunakan di dalam expresi. Presedensi mereka lebih tinggi dari kebanyakan operasi aritmatika lainnya.

Misalnya:

```js run
let counter = 1;
alert( 2 * ++counter ); // 4
???```

Bandingkan dengan:

```js run
let counter = 1;
alert( 2 * counter++ ); // 2, karena counter++ mengembalikan nilai "lama"
???```

Meski secara teknis OK, notasi macam ini biasanya membuat kode kurang dapat dibaca. Satu baris melakukan banyak hal -- tak baik.

Sambil membaca kode, dan melihatnya secara sekilas kita bisa saja melewatkan kode seperti `counter++` dan tidak akan jelas bahwa nilai variabel telah bertambah.

Jadi direkomendasikan menuliskan kode dengan gaya "satu baris -- satu aksi":

```js run
let counter = 1;
alert( 2 * counter );
counter++;
???```

Operator bitwise

Operator bitwise memperlakukan argumen sebagai angka integer 32-bit dan bekerja pada level representasi biner mereka.

Operator ini bukan spesifik JavaScript. Mereka didukung di banyak bahasa pemrograman.

Daftar operator:

  • AND ( & )
  • OR ( | )
  • XOR ( ^ )
  • NOT ( ~ )
  • LEFT SHIFT ( << )
  • RIGHT SHIFT ( >> )
  • ZERO-FILL RIGHT SHIFT ( >>> )

Operator seperti diatas sangat jarang digunakan, ketika kita membutuhkan untuk memainkan angka di level paling rendah (bitwise). Kita tidak akan membutuhkan operator seperti ini dalam waktu dekat, sebagaimana dalam pengembangan web penggunaan operator seperti itu lebih sedikit, tetapi di area yang spesial, seperti kriptographi, operator seperti itu sangan dibutuhkan. Kamu bisa membaca artikel Bitwise Operators di MDN ketika kamu membutuhkannya.

Koma

Operator koma , ialah satu dari banyak operator paling langka dan tak biasa. Kadang, ia digunakan untuk menulis kode lebih pendek, jadi kita harus tahu itu untuk memahami apa yang terjadi.

Operator koma memperbolehkan untuk mengevaluasi beberapa expresi, membagi mereka dengan koma ,. Each of them is evaluated but only the result of the last one is returned.

Misalnya:

let a = (1 + 2, 3 + 4);

alert( a ); // 7 (hasil dari 3 + 4)

Di sini, expresi pertama 1 + 2 dievaluasi dan hasilnya dibuang. Lalu, 3 + 4 dievaluasi dan dikembalikan sebagai hasilnya.

Koma punya presedensi sangat kecil

Harap ingat bahwa operator koma punya presedensi sangat kecil, lebih kecil dari =, jadi tanda kurung penting dalam contoh di atas.

Tanpa mereka: a = 1 + 2, 3 + 4 mengevaluasi + terlebih dahulu, menjumlahkan mereka menjadi a = 3, 7, lalu operator penetapan = menetapkan a = 3, dan sisanya diabaikan. Ini seperti (a = 1 + 2), 3 + 4.

Kenapa kita butuh operator yang membuang semuanya kecuali expresi terakhir?

Kadang, orang memakai itu dalam konstruksi rumit untuk menaruh beberapa aksi dalam satu baris.

Misalnya:

// tiga operasi dalam satu baris
for (a = 1, b = 3, c = a * b; a < 10; a++) {
 ...
}

Trik macam ini dipakai di banyak framework JavaScript. Itulah kenapa kita membahas mereka. Tapi, biasanya, mereka tak membuat kode mudah dibaca sehingga kita sebaiknya pikir-pikir dulu sebelum menggunakan mereka.

Tugas

Berapa nilai final dari semua variabel a, b, c dan d setelah kode berikut?

let a = 1, b = 1;

let c = ++a; // ?
let d = b++; // ?

Jawabannya adalah:

  • a = 2
  • b = 2
  • c = 2
  • d = 1
let a = 1, b = 1;

alert( ++a ); // 2, bentuk prefix mengembalikan nilainya
alert( b++ ); // 1, bentuk postfix mengembalikan nilai lamanya

alert( a ); // 2, diinkremen sekali
alert( b ); // 2, diinkremen sekali

Berapa nilai dari a dan x setelah kode berikut?

let a = 2;

let x = 1 + (a *= 2);

Jawabannya adalah:

  • a = 4 (dikali 2)
  • x = 5 (dikalkulasi sebagai 1 + 4)

Apa hasil dari expresi ini?

"" + 1 + 0
"" - 1 + 0
true + false
6 / "3"
"2" * "3"
4 + 5 + "px"
"$" + 4 + 5
"4" - 2
"4px" - 2
"  -9  " + 5
"  -9  " - 5
null + 1
undefined + 1
" \t \n" - 2

Pikirkan dengan baik, tulis dan bandingkan dengan jawaban.

"" + 1 + 0 = "10" // (1)
"" - 1 + 0 = -1 // (2)
true + false = 1
6 / "3" = 2
"2" * "3" = 6
4 + 5 + "px" = "9px"
"$" + 4 + 5 = "$45"
"4" - 2 = 2
"4px" - 2 = NaN
"  -9  " + 5 = "  -9  5" // (3)
"  -9  " - 5 = -14 // (4)
null + 1 = 1 // (5)
undefined + 1 = NaN // (6)
" \t \n" - 2 = -2 // (7)
  1. Penambahan dengan string "" + 1 mengkonversi 1 ke string: "" + 1 = "1", dan kita punya "1" + 0, aturan yang sama berlaku.
  2. Pengurangan - (seperti kebanyakan operasi matematika) cuma berjalan dengan angka, ia mengkonversi string kosong "" ke 0.
  3. Penambahan dengan string mengappend angka 5 ke string.
  4. Pengurangan selalu mengkonversi ke angka, jadi ia membuat " -9 " menjadi angka -9 (mengabaikan spasi sekitarnya).
  5. null menjadi 0 setelah konversi numerik.
  6. undefined menjadi NaN setelah konversi numerik.
  7. Karakter spasi, ialah string yang depan dan belakangnya ditrim ketika string dikonversi ke angka. Berikut seluruh string berisi karakter spasi, seperti \t, \n dan spasi ???reguler??? di antaranya. Jadi, serupa dengan string kosong, ia menjadi 0.

Ini adalah kode yang menanyakan pengguna untuk memasukan dua angka dan menampilkan jumlahnya.

Kodenya tidak berjalan dengan semestinya. Keluaran dari contoh kode dibawah adalah 12 (nilai dimasukan secara default didalam kotak prompt).

Kenapa? Benarkan. Hasilnya haruslah 3.

let a = prompt("Angka pertama?", 1);
let b = prompt("Angka kedua?", 2);

alert(a + b); // 12

Alasannya adalah karena kotak prompt mengembalikan inputan dari user sebagai string.

Jadi nilai dari masing-masing variabel adalah "1" dan "2".

let a = "1"; // prompt("Angka pertama?", 1);
let b = "2"; // prompt("Angka kedua?", 2);

alert(a + b); // 12

Apa yang kita harus lakukan untuk mengubah string menjadi angka sebelum +, gunakan Number() atau menambahkannya dengan +.

Contoh, tepat sebelum prompt:

let a = +prompt("Angka pertama?", 1);
let b = +prompt("Angka kedua?", 2);

alert(a + b); // 3

Atau didalam alert:

let a = prompt("Angka pertama?", 1);
let b = prompt("Angka kedua?", 2);

alert(+a + +b); // 3

Menggunakan unary dan binary + dicontoh kode terakhir terlihat lucu, kan?

Peta tutorial