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:
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 ${…}:
Kelebihan backtick yang lain yaitu backtick memperbolehkan sebuah string untuk terdiri lebih dari satu 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:
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:
Sebagai contoh, kedua baris berikut sama saja, hanya ditulis dengan cara yang berbeda:
Ada karakter spesial lain, tetapi mereka jarang digunakan
Berikut adalah daftar lengkapnya:
| \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:
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:
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:
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 \\:
Panjang string
Properti length memiliki panjang dari string:
Perlu diingat bahwa \n adalah sebuah karakter spesial, jadi panjang dari string adalah 3.
Orang 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:
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:
Kita juga bisa mengakses karakter per karakter menggunakan sintaks for..of:
String bersifat tidak dapat diubah
Nilai string tidak dapat diubah di Javascript. Tak mungkin mengubah sebuah karakter.
Mari kita coba buktikan:
Salah satu cara untuk mengatasi hal tersebut adalah untuk membuat string baru lalu memasukkan nilainya ke str.
Sebagai contoh:
Di bab ini kita akan melihat contoh lebih banyak dari ini.
Mengganti case
Metode toLowerCase() dan toUpperCase() mengganti case:
Atau, apabila kita hanya ingin sebuah karakter yang diubah menjadi huruf kecil:
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:
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:
Jika kita tertarik dengan semua kemunculan, kita bisa menjalankan indexOf di dalam loop. Setiap panggilan dibuat dengan posisi setelah kemunculan sebelumnya:
Algoritma yang sama dapat ditulis lebih pendek:
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:
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:
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:
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:
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:
Parameter opsinal kedua dari str.includes adalah posisi dimana pencarian mulai dilakukan:
Method str.startsWith dan str.endsWith melakukan fungsi seperti namanya:
Mengambil substring
Ada 3 cara untuk mengambil sebuah substring di Javascript: substring, substr dan slice.
str.slice(start [, end])Mengembalikan bagian dari string dari start sampai (tapi tidak termasuk) end.
Sebagai contoh:
Jika tidak ada parameter kedua, maka slice akan mengambil semua bagian dari start sampai akhir string:
Nilai negatif untuk start/end juga bisa digunakan. Nilai negatif berarti posisinya dihitung dari akhir string:
Mengembalikan bagian dari string di antara start dan end.
Method ini hampir sama dengan slice, tetapi nilai start boleh lebih besar daripada end.
Sebagai contoh:
Parameter negatif tidak didukung (tidak seperti slice), mereka dianggap sebagai 0.
str.substr(start [, length])Mengembalikan substring dari start, dengan panjang length.
Dibandingkan dengan cara-cara sebelumnya, cara ini memperbolehkan kita untuk menyebutkan length alih-alih posisi akhir dari string:
Parameter pertama mungkin bernilai negatif, untuk menghitung dari akhir string:
Mari kita review cara-cara tersebut untuk menghindari kebingungan:
| slice(start, end) | dari start sampai end (tidak termasuk end) | nilai negatif diperbolehkan |
| substring(start, end) | antara start dan end | nilai negatif berarti mean 0 |
| substr(start, length) | dari start ambil length karakter | start negatif diperbolehkan |
Semuanya dapat melakukan pekerjaannya. Secara formal, substr memiliki kekurangan: fungsi ini tidak tercantum di spesifikasi inti Javascript, tetapi di Annex B, yang mencakup hanya fitur browser yang ada karena alasan historis. Jadi, environment non-browser mungkin gagal untuk mendukungnya. Tetapi dalam praktik fungsi ini bekerja di mana saja.
Dibandingkan dengan dua varian yang lain, slice lebih fleksibel, karena memperbolehkan parameter negatif dan lebih pendek untuk ditulis. Jadi, dari ketiga cara sudah cukup untuk mengingat slice.
Membandingkan string
Seperti yang kita tahu dari bab Perbandingan, string dibandingkan karakter per karakter dengan urutan alfabet.
Akan tetapi, ada beberapa pengecualian.
-
Huruf kecil selalu lebih besar dibanding huruf kapital:
alert( 'a' > 'Z' ); // true -
Karakter dengan tanda diakritik “tidak sesuai urutan”:
alert( 'Österreich' > 'Zealand' ); // trueHal ini dapat menyebabkan hasil yang aneh apabila kita mengurutkan nama-nama negara. Biasanya orang mengharapkan Zealand muncul setelah Österreich di daftar.
Untuk memahami apa yang terjadi, mari kita review representasi internal string di Javascript.
Semua string menggunakan encoding UTF-16. Yaitu: setiap karakter memiliki masing-masing kode numerik. Ada method spesial yang memperbolehkan kita untuk mengambil karakter dari kode dan sebaliknya.
str.codePointAt(pos)Mengembalikan kode untuk karakter pada posisi pos:
Membuat sebuah karakter berdasarkan code numeriknya
Kita juga dapat membuat karakter unicode dengan kode mereka menggunakan \u yang diikuti oleh kode heksadesimal:
Sekarang mari kita lihat karakter dengan kode di antara 65..220 (alfabet latin dan sedikit tambahan) dengan membuat string yang terdiri dari mereka:
Kan? Huruf kapital muncul pertama, lalu beberapa karakter spesial, lalu huruf kecil, dan Ö berada di dekat akhir string.
Sekarang terlihat jelas kenapa a > Z.
Karakter-karakter dibandingkan berdasarkan kode numeriknya. Kode yang lebih besar berarti karakter tersebut lebih besar. Kode untuk a (97) lebih besar dibandingkan dengan kode untuk Z (90).
- Semua huruf kecil muncul setelah huruf kapital karena kode mereka lebih besar.
- Beberapa karakter seperti Ö terpisah dari alfabet utama. Disini, kodenya lebih besar dibandingkan semua karakter dari a to z.
Perbandingan yang benar
Algoritma yang “benar” untuk melakukan perbandingan string lebih kompleks dari kelihatannya, setiap bahasa memiliki alfabet mereka masing-masing.
Jadi, browser harus tahu bahasa yang digunakan untuk perbandingan.
Beruntungnya, semua browser modern (IE10- memerlukan library tambahan Intl.JS) mendukung standar internasionalisasi ECMA 402.
Hal tersebut menyediakan cara spesial untuk membandingkan stringi di berbeda bahasa, mengikuti peraturan mereka.
Method str.localeCompare(str2) mengembalikan sebuah interger yang menandakan apakah str lebih kecil, sama dengan atau lebih besar dari str2 menurut peraturan-peraturan bahasa:
- Mengembalikan nilai negatif jika str lebih kecil dibandingkan str2
- Mengembalikan nilai positif jika str lebih besar dibandingkan str2
- Mengembalikan 0 apabila mereka sama.
Seperti contoh:
Method ini sebenarnya menerima 2 argumen tambahan yang disebutkan di dokumentasi, yang memperbolehkan untuk menyebutkan bahasa (yang biasanya diambil dari environment, urutan huruf bergantung dari bahasa) dan menyebutkan peraturan-peraturan tambahan seperti case sensitivity atau apakah "a" and "á" dianggap sama dan seterusnya.
Bagian internal dari unicode
Bagian ini membahas lebih dalam tentang bagian internal string. Pengetahuan ini akan berguna apabila Anda akan berurusan dengan emoji, simbol matematika, hieroglif, atau simbol-simbol lain yang langka.
Anda dapat melewati bagian ini jika tidak berurusan dengan mereka.
Surrogate pairs
Semua karakter yang sering digunakan memiliki kode 2-byte. Huruf di kebanyakan negara eropa, angka, dan bahkan kebanyakan hieroglif, memiliki representasi 2-byte.
Tetapi 2 byte hanya memperbolehkan 65536 kombinasi dan itu tidak cukup untuk semua kombinasi simbol. Jadi simbol-simbol yang langka menggunakan encoding dengan sepasang karakter 2-byte yang disebut “surrogate pair”.
Panjang dari simbol tersebut adalah 2:
Perlu diingat bahwa surrogate pair tidak ada pada saat Javascript dibuat, oleh karena itu fitur ini tidak diproses secara benar oleh bahasa ini!
Kita sebenarnya memiliki sebuah simbol di setiap string di atas, tetapi length menunjukkan panjang 2.
String.fromCodePoint dan str.codePointAt adalah beberapa method yang menangani surrogate pair dengan benar. Belum lama ini mereka muncul di bahasa ini. Sebelum mereka, hanya ada String.fromCharCode dan str.charCodeAt. Method-method tersebut sebenarnya sama saja dengan fromCodePoint/codePointAt, tetapi tidak bisa digunakan untuk surrogate pair.
Mengambil sebuah simbol terkadang agak susah, karena surrogate pair diperlakukan sebagai dua karakter:
Perlu diingat bahwa bagian dari surrogate pair tidak memiliki arti tanpa pasangan yang lain. Jadi contoh di atas menampilkan karakter aneh.
Secara teknis, surrogate pair juga dapat dideteksi berdasarkan kode mereka, jika sebuah karakter memiliki kode di antara 0xd800..0xdbff, maka karakter ini adalah bagian pertama dari surrogate pair. Karakter selanjutnya (bagian kedua) harus berada di antara 0xdc00..0xdfff. Interval ini sudah dipesan secara khusus untuk surrogate pair oleh standar.
Pada kasus diatas:
Anda akan menemukan cara lain untuk bertanganan dengan surrogate pair nanti di bab Iterables / Bisa di iterasi. Mungkin juga ada library-library yang untuk hal tersebut, tetapi tidak ada yang cukup terkenal untuk disarankan di sini.
Tanda diakritik dan normalisasi
Di banyak bahasa terdapat simbol-simbol yang terdiri dari huruf dasar dengan tanda di atas/bawahnya.
Sebagai contoh, karakter a dapat menjadi huruf dasar untuk: àáâäãåā. Kebanyakan karakter “komposit” memiliki kode mereka sendiri di tabel UTF-16. Hal tersebut tidak selalu terjadi, karena terlalu banyak kemungkinan kombinasi.
Untuk mendukung komposisi yang fleksibel, UTF-16 memperbolehkan kita untuk menggunakan beberapa karakter unicode: sebuah huruf dasar yang diikuti oleh satu atau lebih karakter “tanda” yang “menghiasinya”.
Sebagai contoh, jika kita memiliki S diikuti dengan karakter spesial “titik di atas” (kode \u0307), maka akan ditampilkan Ṡ.
Jika kita memerlukan tanda tambahan di atas huruf (atau di bawahnya) – tidak masalah, tambahkan saja karakter tanda yang diperlukan.
Sebagai contoh, jika kita tambahkan sebuah karakter “titik di bawah” (kode \u0323), maka kita akan mendapatkan “S dengan titik di atas dan di bawah”: Ṩ.
Sebagai contoh:
Hal tersebut memberikan banyak fleksibilitas, tetapi juga masalah yang menarik: dua karakter mungkin terlihat sama, tetapi dapat direpresentasikan dengan komposisi unicode yang berbeda.
Sebagai contoh:
Untuk menyelesaikan masalah ini, terdapat sebuah algoritma “normalisasi unicode” yang membuat setiap string menjadi satu bentuk “normal”.
Algoritma tersebut diimplementasikan oleh str.normalize().
Agak lucu bahwa di situasi kita normalize() menjadikan sekumpulan karakter dengan panjang 3 menjadi satu: \u1e68 (S dengan dua titik).
Pada kenyataan, hal ini tidak selalu berlaku. Contoh diatas berlaku karena simbol Ṩ is “cukup sering digunakan”, jadi pembuat UTF-16 memasukkannya di tabel utama dan memberinya sebuah kode.
Jika Anda ingin belajar lebih lanjut tentang aturan normalisasi dan variasinya – mereka dideskripsikan di appendix Unicode standard: Unicode Normalization Forms, tetapi untuk kebanyakan kasus informasi yang terdapat di bagian ini sudah cukup.
Kesimpulan
- Terdapat 3 jenis tanda petik. Backtick membolehkan string memiliki baris ganda dan menyisipkan expresi ${…}.
- String di Javascript diencode menggunakan UTF-16.
- Kita bisa memakai karakter seperti \n dan memasukkan karakter berdasarkan unicode mereka menggunakan \u....
- Untuk mendapatkan karakter, gunakan: [].
- Untuk mendapatkan substring, gunakan: slice atau substring.
- Untuk mengubah case kecil/besar dari string, gunakan: toLowerCase/toUpperCase.
- Untuk mencari substring, gunakan: indexOf, atau includes/startsWith/endsWith untuk pengecekan sederhana.
- Untuk membandingkan string mengikuti bahasa, gunakan localeCompare, jika tidak mereka akan dibandingkan berdasarkan kode karakter.
Ada beberapa metode string lain yang berguna:
- str.trim() – menghilangkan (“memotong”) spasi dari awal dan akhir dari sebuah string.
- str.repeat(n) – mengulang string sebanyak n kali.
- …dan masih banyak lagi yang dapat ditemukan di dalam manual.
String juga memiliki method-method untuk mencari/mengganti dengan ekspresi reguler (regular expression). Tetapi itu adalah topik yang luas, jadi topik ini dibahas di bagiannya sendiri Regular expressions.
komentar