Di Javascript, data teks disimpan sebagai string. Tidak ada tipe data sendiri untuk satu buah karakter.
UTF-16 selalu digunakan sebagai format internal string, hal tersebut tidak terikat dengan jenis encoding yang digunakan oleh halaman.
Petik
Mari kita lihat berbagai jenis petik.
String dapat ditutup dengan petik satu, petik dua, maupun backtick:
let single = 'single-quoted';
let double = "double-quoted";
let backticks = `backticks`;
Petik satu dan petik dua kurang lebih hampir sama. Akan tetapi backtick memiliki perbedaan, yaitu memperbolehkan kita untuk menyisipkan ekspresi ke dalam string, dengan menaruhnya di dalam ${…}:
function sum(a, b) {
return a + b;
}
alert(`1 + 2 = ${sum(1, 2)}.`); // 1 + 2 = 3.
Kelebihan backtick yang lain yaitu backtick memperbolehkan sebuah string untuk terdiri lebih dari satu baris:
let guestList = `Guests:
* John
* Pete
* Mary
`;
alert(guestList); // list tamu, dipisahkan per baris
Lebih rapi, kan? Tetapi petik satu atau dua tidak bekerja seperti itu.
Jika kita coba untuk menggunakan mereka untuk lebih dari satu baris, akan terjadi error:
let guestList = "Guests: // Error: Unexpected token ILLEGAL
* John";
Petik satu dan petik dua berasal dari masa lalu saat bahasa pemrograman dibuat, dimana kebutuhan untuk string lebih dari satu baris belum dipikirkan. Backtick muncul di kemudian hari, dan lebih fleksibel.
Backtick juga memperbolehkan kita untuk menspesifikasi “fungsi template” sebelum backtick pertama. Syntaxnya yaitu: func`string`. Fungsi func dipanggil secara otomatis, menerima string dan ekspresi yang berada di dalamnya dan bisa memproses mereka. Ini disebut “tagged templates”. Fitur ini membuat implementasi kustom templating lebih mudah, tapi jaran dipakai dalam praktik. Kamu bisa membaca lebih tentang ini di manual.
Karakter spesial
Masih mungkin untuk membuat string dengan banyak baris menggunakan petik satu atau petik dua dengan menggunakan “karakter newline”, ditulis seperti berikut \n, yang menandakan baris baru:
let guestList = "Guests:\n * John\n * Pete\n * Mary";
alert(guestList); // list tamu yang dipisahkan per baris
Sebagai contoh, kedua baris berikut sama saja, hanya ditulis dengan cara yang berbeda:
let str1 = "Hello\nWorld"; // dua baris menggunakan "simbol baris baru"
// dua baris menggunakan backtick
let str2 = `Hello
World`;
alert(str1 == str2); // true
Ada karakter spesial lain, tetapi mereka jarang digunakan
Berikut adalah daftar lengkapnya:
| Character | Description |
|---|---|
\n |
Baris baru |
\r |
Carriage return: tidak digunakan sendiri. File teks milik di Windows menggunakan kombinasi dari dua karakter \r\n untuk menandakan baris baru. |
\', \" |
Petik-petik |
\\ |
Backslash |
\t |
Tab |
\b, \f, \v |
Backspace, Form Feed, Vertical Tab – tetap bisa digunakan untuk kompabilitas, sekarang sudah tidak digunakan. |
\xXX |
Karakter unicode dengan nilai heksadesimal XX, misalnya '\x7A' itu sama saja dengan 'z'. |
\uXXXX |
Sebuah simbol unicode dengan nilai heksadesimal XXXX di dalam encoding UTF-16, sebagai contoh \u00A9 – adalah sebuah unicode untuk simbol copyright ©. Simbol ini harus terdiri dari 4 digit heksadesimal. |
\u{X…XXXXXX} (1 to 6 karakter heksadesimal) |
Sebuah simbol unicode dengan encoding UTF-32. Beberapa karakter langka menggunakan dua simbol unicode, yang memakan 4 byte. Dengan cara ini kita dapat menggunakan kode yang panjang. |
Contoh dengan unicode:
alert( "\u00A9" ); // ©
alert( "\u{20331}" ); // 佫, sebuah karakter mandarin (unicode panjang)
alert( "\u{1F60D}" ); // 😍, sebuah simbol wajah tersenyum (unicode panjang lainnya)
Karakter-karakter spesial yang diawali dengan karakter backslash \ kadang dipanggil dengan sebutan “escape character”.
Kita kadang dapat menggunakannya apabila kita ingin menggunakan petik di dalam string.
Misalnya:
alert( 'I\'m the Walrus!' ); // I'm the Walrus!
Seperti yang kita lihat, kita harus menambahkan backslash di depan petik yang di dalam string \', karena jika tidak petik tersebut akan menandakan akhir dari sebuah string.
Tentu saja, hanya jenis petik yang sama dengan penutup string yang perlu di “escape”. Jadi, solusi yang lebih elegan yaitu mengganti petik satu menjadi petik dua atau backtick:
alert( `I'm the Walrus!` ); // I'm the Walrus!
Ingat bahwa backslash \ hanya dipakai untuk Javascript agar dapat membaca string dengan benar. Di dalam memori, string tidak memiliki \. Anda dapat melihatnya secara langsung pada contoh alert di atas.
Tetapi bagaimana jika kita ingin menampilkan backslash \ di dalam sebuah string?
Hal tersebut bisa dilakukan, tetapi kita harus menulisnya dua kali seperti ini \\:
alert( `The backslash: \\` ); // The backslash: \
Panjang string
Properti length memiliki panjang dari string:
alert( `My\n`.length ); // 3
Perlu diingat bahwa \n adalah sebuah karakter spesial, jadi panjang dari string adalah 3.
length adalah sebuah propertiOrang dengan latar belakang di bahasa pemrograman lain kadang salah mengetik str.length() alih-alih str.length. Hal tersebut tidak bekerja.
Perlu diingat bahwa str.length adalah properti numerik, bukan sebuah fungsi. Tidak perlu menambahkan kurung di belakangnya.
Mengakses karakter di dalam string
Untuk mengakses karakter pada posisi pos, digunakan kurung kotak [pos] atau dengan method str.charAt(pos). Karakter pertama dimulai dari posisi ke-0:
let str = `Hello`;
// karakter pertama
alert( str[0] ); // H
alert( str.charAt(0) ); // H
// karakter terakhir
alert( str[str.length - 1] ); // o
Kurung kotak adalah cara modern untuk mengakses sebuah karakter, sementara charAt ada karena alasan historis.
Perbedaan satu-satunya di antara mereka adalah apabila tidak ada karakter yang ditemukan, [] mengembalikan undefined, dan charAt mengembalikan string kosong:
let str = `Hello`;
alert( str[1000] ); // undefined
alert( str.charAt(1000) ); // '' (string kosong)
Kita juga bisa mengakses karakter per karakter menggunakan sintaks for..of:
for (let char of "Hello") {
alert(char); // H,e,l,l,o (char bernilai "H", lalu "e", lalu "l", dan seterusnya)
}
String bersifat tidak dapat diubah
Nilai string tidak dapat diubah di Javascript. Tak mungkin mengubah sebuah karakter.
Mari kita coba buktikan:
let str = 'Hi';
str[0] = 'h'; // galat
alert( str[0] ); // tidak bekerja
Salah satu cara untuk mengatasi hal tersebut adalah untuk membuat string baru lalu memasukkan nilainya ke str.
Sebagai contoh:
let str = 'Hi';
str = 'h' + str[1]; // mengganti nilai string
alert( str ); // hi
Di bab ini kita akan melihat contoh lebih banyak dari ini.
Mengganti case
Metode toLowerCase() dan toUpperCase() mengganti case:
alert( 'Interface'.toUpperCase() ); // INTERFACE
alert( 'Interface'.toLowerCase() ); // interface
Atau, apabila kita hanya ingin sebuah karakter yang diubah menjadi huruf kecil:
alert( 'Interface'[0].toLowerCase() ); // 'i'
Mencari substring
Ada banyak cara untuk mencari sebuah substring di dalam sebuah string.
str.indexOf
Cara yang pertama yaitu str.indexOf(substr, pos).
Method ini mencari substr di dalam str, mulai dari posisi pos yang diberikan, dan mengembalikan posisi dimana substring ditemukan atau -1 jika tidak ditemukan.
Misalnya:
let str = 'Widget with id';
alert( str.indexOf('Widget') ); // 0, karena 'Widget' ditemukan di awal string
alert( str.indexOf('widget') ); // -1, tidak ditemukan, karena pencarian bersifat case-sensitive
alert( str.indexOf("id") ); // 1, "id" ditemukan pada posisi 1 (..idget with id)
Parameter kedua yang opsional memperbolehkan kita untuk mencari dari posisi yang ditentukan.
Misalnya, kemunculan pertama "id" ada di posisi 1. Untuk mencari kemunculan berikutnya, ayo kita mulai pencarian dari posisi 2:
let str = 'Widget with id';
alert( str.indexOf('id', 2) ) // 12
Jika kita tertarik dengan semua kemunculan, kita bisa menjalankan indexOf di dalam loop. Setiap panggilan dibuat dengan posisi setelah kemunculan sebelumnya:
let str = 'As sly as a fox, as strong as an ox';
let target = 'as'; // mari kita cari
let pos = 0;
while (true) {
let foundPos = str.indexOf(target, pos);
if (foundPos == -1) break;
alert( `Found at ${foundPos}` );
pos = foundPos + 1; // lanjutkan pencarian dari posisi berikutnya
}
Algoritma yang sama dapat ditulis lebih pendek:
let str = "As sly as a fox, as strong as an ox";
let target = "as";
let pos = -1;
while ((pos = str.indexOf(target, pos + 1)) != -1) {
alert( pos );
}
str.lastIndexOf(substr, position)Ada juga method yang hampir sama str.lastIndexOf(substr, position) yang mencari dari akhir sebuah string sampai ke awalnya.
Cara tersebut akan menemukan kemunculan dalam urutan yang terbalik.
Ada sedikit kerepotan dalam menggunakan indexOf di dalam if. Kita tidak dapat menggunakannya seperti ini:
let str = "Widget with id";
if (str.indexOf("Widget")) {
alert("We found it"); // tidak bekerja!
}
Contoh di atas tidak bekerja karena str.indexOf("Widget") mengembalikan 0 (artinya kemunculan ditemukan di awal string). if menganggap 0 sebagai false.
Jadi, kita harus mengecek dengan nilai -1, seperti ini:
let str = "Widget with id";
if (str.indexOf("Widget") != -1) {
alert("We found it"); // kalau sekarang berhasil!
}
Trik bitwise NOT
Salah satu trik lama yang digunakan disini adalah operator bitwise NOT ~. Operator ini mengubah angka menjadi integer 32-bit (menghilangkan bagian desimal jika ada) lalu menegasikan semua bit pada representasi binernya.
Dalam praktik, hal tersebut berarti: untuk integer 32-bit ~n sama dengan -(n+1).
Sebagai contoh:
alert( ~2 ); // -3, sama dengan -(2+1)
alert( ~1 ); // -2, sama dengan -(1+1)
alert( ~0 ); // -1, sama dengan -(0+1)
alert( ~-1 ); // 0, sama dengan -(-1+1)
Seperti yang kita lihat, ~n bernilai nol apabila n == -1 (untuk semua signed integer n).
Jadi, pengecekan di dalam if ( ~str.indexOf("...") ) bernilai benar apabila hasil dari indexOf tidak bernilai -1. Dengan kata lain, jika kemunculan ditemukan.
Orang-orang menggunakannya untuk memperpendek pengecekan indexOf:
let str = "Widget";
if (~str.indexOf("Widget")) {
alert( 'Found it!' ); // bekerja
}
Biasanya tidak direkomendasikan untuk menggunakan fitur bahasa dengan cara yang tidak jelas, tetapi trik ini biasa digunakan di kode yang kuno, jadi kita harus memahaminya.
Ingat: if (~str.indexOf(...)) dibaca sebagai “if ditemukan”.
Untuk lebih detail, karena bilangan yang besar dipotong menjadi 32-bit oleh operator ~, ada angka lain yang memberikan hasil 0, angka yang terkecil yaitu ~4294967295=0. Hal tersebut menyebabkan trik ini benar apabila string yang dites tidak sepanjang itu.
Kita dapat melihat bahwa trik ini hanya digunakan di kode yang kuno, karena Javascript modern menyediakan method .includes (lihat di bawah).
includes, startsWith, endsWith
Method yang lebih modern str.includes(substr, pos) mengembalikan true/false tergantung dengan apakah str mengandung substr di dalamnya.
Ini adalah pilihan yang cocok apabila kita hanya perlu mengetes apakah substr ada, tetapi tidak memerlukan posisinya: