ECMAScript 6
ECMAScript 6
Bahasa JavaScript didefinisikan dalam standar ECMA-262. Bahasa yang didefinisikan menggunakan
standar ini disebut dengan ECMAScript. Browser dan Node.js adalah contoh implementasi dari ECMA-
262/ECMAScript. Kedua platform tersebut (Browser dan Node.js) menggunakan bahasa JavaScript
dengan fungsionalitas yang berbeda. Bagi browser, JavaScript digunakan untuk membantu website
menjadi lebih interaktif. Sedangkan bagi Node.js, JavaScript digunakan untuk pengembangan aplikasi
diluar dari Browser, seperti Server, Desktop, Mobile, bahkan Game. Sehingga Browser dan Node.js
memberikan fungsionalitas lain dengan menambahkan objek dan method sesuai kebutuhan masing -
masing.
Namun kembali lagi, bahwa inti dari JavaScript itu sendiri didefinisikan dalam ECMAScript. Tak heran,
pengembangan dari ECMA-262 menjadi sangat vital dalam menentukan kesuksesan bahasa JavaScript.
Sejarah singkat JavaScript
Merunut sejarah, sebenarnya pada tahun 1995 Netscape melahirkan bahasa pemrograman ini dengan
nama “LiveScript”, namun pada saat itu bahasa pemrograman Java sedang populer.
Netspace dan Sun selaku pengembang bahasa pemrograman Java (saat ini Oracle) melakukan perjanjian
lisensi dan mengubah penamaan LiveScript menjadi JavaScript. Setelah diadopsi di luar Netscape,
JavaScript distandarisasi oleh European Computer Manufacturer’s Association (ECMA). Itulah sebabnya
terkadang ada yang menyebutnya dengan ECMAScript.
Terdapat beberapa versi dari JavaScript. Pada tahun 2000 - 2010, ECMAScript 3 (ES3) merupakan versi
yang banyak digunakan ketika JavaScript sedang mendominasi. Selama waktu tersebut, ECMAScript 4
(ES4) sedang dalam proses pengembangan dengan harapan akan memberikan improvisasi yang cukup
signifikan, namun ambisi tersebut tidak berjalan mulus sehingga pada tahun 2008 pengembangan ES4
ditinggalkan.
Walaupun begitu, itu bukan akhir dari JavaScript. Pengembangan digantikan dengan ECMAScript 5
(ES5) dengan mengurangi ambisinya. Seperti apa? perbaikan hanya terbatas pada hal non-kontroversial.
Pembaruan tersebut berhasil dan akhirnya ES5 pun rilis pada tahun 2009.
Akhirnya pada tahun 2015 ECMAScript 6 (ES6) rilis dengan membawa perubahan yang cukup besar
termasuk ide - ide yang sudah direncanakan untuk versi 4.
Saat ini JavaScript sudah menyentuh versi ECMAScript 10 (ES10), akan tetapi mulai dari pembaharuan
ES6, JavaScript hanya melakukan update tahunan yang bersifat minor. Kita bisa lihat rincian updatenya
pada laman wikipedia berikut.
Pada modul kali ini kita akan membahas beberapa pembaharuan besar yang ada pada ES6, mulai dari
deklarasi variabel, template string, function syntax, class, promise, hingga module.
Perbedaanya antara let dan const adalah jika kita menggunakan let maka variabel tersebut dapat
diinisialisasi ulang nilainya. Sedangkan const tidak bisa, sehingga jika kita menggunakan const pastikan
kita langsung menginisialisasi nilai dari variabel tersebut.
Jadi intinya kapan kita harus menggunakan let dan const? Untuk aturan umum penggunaanya adalah
sebagai berikut:
Gunakan let ketika variabel yang kita buat akan diinisialisasikan kembali nilainya.
Gunakan const ketika variabel yang kita buat tidak ingin diinisialisasikan kembali nilainya.
const merupakan cara yang paling ketat dalam membuat variabel, sehingga pastikan kita menggunakan
const jika memang kita tidak berencana untuk menginisialisasikan kembali nilainya.
Ada sedikit catatan, bahwa mengubah dan menginisialisasikan ulang nilai pada variabel merupakan hal
yang berbeda. Kita bisa lihat perbedaanya dengan jelas ketika sebuah variabel tersebut merupakan array
atau objek.
Menginisialisasikan ulang
Membuat variabel dengan const akan membuat variabel tersebut bersifat read-only, tapi bukan berarti
tidak dapat diubah nilainya. Mungkin variabel yang menampung nilai primitif seperti string, number,
boolean akan sulit mengubah nilainya tanpa melalui inisialisasi ulang.
OOP
Dalam paradigma Object-Oriented Programming (OOP), class merupakan sebuah blueprint yang dapat
dikembangkan untuk membuat sebuah objek. Blueprint ini merupakan sebuah template yang di dalamnya
menjelaskan seperti apa perilaku dari objek itu (berupa properti ataupun method).
Teknik dasar ini yang digunakan dalam membuat class di JavaScript sebelum ES6.
“Mengapa method pada instance harus disimpan pada prototype atau __proto__ ? Mengapa tidak
disimpan pada constructor sama seperti properti?
Alasannya adalah jika kita menyimpan method pada constructor maka method tersebut akan selalu dibuat
ketika instance dibuat. Ini bukan pendekatan yang baik karena jika method memiliki kode yang banyak,
maka akan memakan memori yang banyak.
Sedangkan jika menggunakan prototype, method hanya dibuat satu kali. Dan method tersebut diwarisi
kepada setiap instance yang dibuat.”
Oiya pada constructor class Car, kita melihat penggunaan super(), apa itu maksudnya? Keyword super
digunakan untuk mengakses properti dan method yang ada pada induk class ketika berada pada child
class. Jadi super(lisencePlate, manufacture) di atas berarti kita mengakses constructor dari parent class
dan mengirimkan lisencePlate, dan manufacture sebagai data yang dibutuhkan olehnya agar objek
(instance) Car berhasil dibuat.
Penggunaan super sangat berguna ketika kita hendak menjalankan method overriding pada method
parent. Contohnya kita akan melakukan method overriding pada method info() dengan menambahkan
informasi jumlah roda pada mobil, maka kita dapat melakukannya dengan seperti ini:
Asynchronous vs Synchronous
Dalam web development, asynchronous programming merupakan topik yang cukup menantang untuk
dipelajari. Apa pasal? Sebabnya, kita terbiasa dengan kode yang bekerja secara synchronous. Sebelum
kita membahas asynchronous lebih dalam, mungkin sebagian dari kita ada yang belum mengetahui apa
itu asynchronous dan synchronous itu
Dalam synchronous program, jika kita menuliskan dua baris kode maka baris kode yang kedua tidak bisa
dieksekusi sebelum mengeksekusi kode pada baris pertama. Kita bisa bayangkan ini dalam kehidupan
nyata ketika mengantri membeli kopi di sebuah kedai kopi. Kita tidak bisa mendapatkan kopi sebelum
semua antrian di depan kita selesai dilayani, sama hal nya orang yang di belakang kita pun harus
menunggu gilirannya.
Dalam asynchronous program, jika kita menuliskan dua baris kode, kita dapat membuat baris kode kedua
dieksekusi tanpa harus menunggu kode pada baris pertama selesai dieksekusi. Dalam dunia nyata kita
bisa membayangkan dengan memesan kopi namun memesannya melalui pelayan, di mana sembari kita
menunggu pesannya datang, kita dapat melakukan aktivitas lain seperti membuka laptop, menulis, hingga
kopi itu datang dengan sendirinya.
Urutan di mana seseorang mendapatkan minumannya terlebih dahulu memiliki korelasi dengan kapan ia
memesan makanannya. Namun bukan hanya itu, faktor ini juga dipengaruhi dengan minuman apa yang ia
pesan. Contohnya jika kita memesan kopi espresso sedangkan teman kita hanya memesan air mineral,
walaupun kita memesannya terlebih dahulu, tiada jaminan kita akan mendapatkannya duluan. Membuat
espresso tentu akan membutuhkan waktu lebih lama dibandingkan dengan menuangkan air mineral pada
gelas, kan?
Dalam program yang dijalankan secara asynchronous pun demikian. Task yang kecil akan lebih dahulu
selesai dibandingkan dengan task yang besar, meskipun task yang besar lebih dahulu dijalankan.
Callback Hell
Kita sudah mengetahui bahwa callback dibutuhkan untuk mendapatkan nilai yang berasal dari
asynchronous function. Lantas bagaimana jika terdapat proses satu sama lain yang saling bergantungan?
Contohnya, untuk membuat kue tahapan yang perlu kita lakukan adalah:
Mempersiapkan bahan
Membuat adonan
Memanggang adonan
Tahapan tersebut sangat tergantung satu sama lain. Kita tidak bisa memanggang adonan sebelum
membuat adonannya, dan kita tidak bisa membuat adonan tanpa mempersiapkan bahannya terlebih
dahulu. Jika seluruh tahapan tersebut berjalan secara synchronous, mungkin kita bisa melakukanya seperti
ini:
function makeACake(...rawIngredients) {
dough = makeTheDough(ingredients),
pouredDough = pourDough(dough),
cake = bakeACake(pourDough),
console.log(cake);
Namun jika fungsi-fungsi tersebut berjalan secara asynchronous, maka kita akan membuat yang namanya
callback hell. Callback hell terjadi karena banyak sekali callback function yang bersarang karena saling
membutuhkan satu sama lain, sehingga kode akan tampak seperti ini:
function makeACake(...rawIngredients) {
gatheringIngredients(rawIngredients, function(ingridients) {
makeTheDough(ingridients, function(dough) {
pourDough(dough, function(pouredDough) {
bakeACake(pouredDough, function(cake) {
console.log(cake);
});
});
});
});
Melihat kode seperti ini saja, kepala jadi pusing. Terbayang sulitnya memelihara kode ini di masa yang
akan datang.
Lantas apa solusi agar kita dapat menghindari callback hell? Salah satunya adalah dengan menggunakan
Promise.
function makeACake(...rawIngredients) {
gatheringIngredients(rawIngredients)
.then(makeTheDough)
.then(pourDough)
.then(bakeACake)
.then(console.log);
Dengan Promise, kita dapat meminimalisir callback hell dan mengubahnya menjadi kode yang sangat
mudah dibaca. Bahkan dengan kode seperti itu, non-developer pun dapat mengerti apa maksud dari kode
tersebut.
PROMISE
Executor function dapat memiliki dua parameter, yang berfungsi sebagai resolve() dan reject()
function. Berikut penjelasan detailnya:
resolve() merupakan parameter pertama pada executor function. Parameter ini merupakan
fungsi yang dapat menerima satu parameter, biasanya kita gunakan untuk mengirimkan
data ketika promise berhasil dilakukan. Ketika fungsi ini terpanggil, kondisi Promise
akan berubah dari pending menjadi fulfilled.
reject() merupakan parameter kedua pada executor function. Parameter ini merupakan
fungsi yang dapat menerima satu parameter yang digunakan untuk memberikan alasan
mengapa Promise tidak dapat terpenuhi. Ketika fungsi ini terpanggil, kondisi Promise
akan berubah dari pending menjadi rejected.
Web component merupakan salah satu fitur yang ditetapkan standar World Wide Web Consortium
(W3C). Fitur ini memudahkan developer dalam membuat komponen UI websitenya menjadi lebih
modular.
Dengan semakin pesatnya perkembangan website saat ini kita perlu menetapkan teknik yang lebih
modern dalam mengembangkan website. Salah satunya membuat komponen UI pada website agar
mampu sesuai dengan kebutuhan dan digunakan ulang. Kebanyakan developer saat ini menggunakan
framework untuk membantu pengembangan website menjadi mudah dalam membuat dan menggunakan
komponen UI.
Namun apakah Anda tahu beberapa kelebihan web component dibandingkan komponen yang dibuat
menggunakan framework?
Standard : Web Component merupakan standar yang ditetapkan oleh WC3 dalam membuat komponen
yang reusable.
Compatibility : Karena web component merupakan standard maka dapat digunakan pada framework
seperti Angular, React, ataupun Vue.
Simple : Menggunakan web component tidak memerlukan konfigurasi khusus layaknya framework
yang ada. Karena web component dibangun tak lain hanya menggunakan JS/CSS/HTML murni.
Web component bersifat reusable. Bahkan dapat digunakan walaupun kita menggunakan framework
sekalipun. Apa pasal? Web component dibangun tak lain menggunakan JS/HTML/CSS murni. Terdapat
dua API penting dalam menerapkan web component, yakni:
Custom Elements: Digunakan untuk membuat elemen baru (custom element). Kita juga bisa
menentukan perilaku element tersebut sesuai kebutuhan.
Shadow DOM: Digunakan untuk membuat HTML element terenkapsulasi dari gangguan luar.
Biasanya digunakan pada custom element, agar elemen tersebut tidak terpengaruh oleh styling yang
ditetapkan di luar dari custom elemen-nya.
Ketika sebuah JavaScript class mewarisi sifat dari HTMLElement maka class tersebut akan
memiliki siklus hidup layaknya sebuah elemen HTML. Kita dapat menerapkan logika pada
setiap siklus hidup yang ada dengan memanfaatkan lifecycle callbacks yang ada. Berikut ini
lifecycle callbacks yang ada pada HTMLElement:
Untuk mempermudah memahami urutan siklus hidup element pada HTML kita bisa lihat pada
ilustrasi berikut:
Walaupun sebenarnya constructor() bukan termasuk siklus hidup HTML Element, namun fungsi
tersebut sering digunakan untuk melakukan konfigurasi awal ketika pertama kali element dibuat.
Seperti menentukan event listener, atau menetapkan Shadow DOM.
Ketika kita mengimplementasikan constructor pada custom element, kita wajib memanggil
method super(). Jika tidak, maka akan menghasilkan error:
DOM
Shadow DOM dapat mengisolasi sebagian struktur DOM di dalam komponen sehingga tidak
dapat disentuh dari luar komponen atau nodenya. Singkatnya kita bisa sebut Shadow DOM
sebagai “DOM dalam DOM”. Bagaimana ia bekerja? Perhatikan ilustrasi berikut:
Shadow DOM dapat membuat DOM Tree lain terbentuk secara terisolasi melalui host yang
merupakan komponen dari regular DOM Tree (Document Tree). Shadow DOM Tree ini dimulai
dari root bayangan (Shadow root), yang dibawahnya dapat memiliki banyak element lagi
layaknya Document Tree.
Terdapat beberapa terminologi yang perlu kita ketahui dari ilustrasi di atas:
Shadow host : Merupakan komponen/node yang terdapat pada regular DOM di mana
shadow DOM terlampir pada komponen/node ini.
Shadow tree : DOM Tree di dalam shadow DOM.
Shadow boundary : Batas dari shadow DOM dengan regular DOM.
Shadow root : Root node dari shadow tree.
Kita dapat memanipulasi elemen yang terdapat di dalam shadow tree layaknya pada document
tree, namun cakupannya selama kita berada di dalam shadow boundary. Dengan kata lain, jika
kita berada di document tree kita tidak dapat memanipulasi elemen bahkan menerapkan styling
pada elemen yang terdapat di dalam shadow tree. Itulah mengapa shadow DOM dapat membuat
komponen terenkapsulasi.