JavaScript Programming
JavaScript merupakan bahasa pemrograman yang populer digunakan untuk mengembangkan sebuah website bersama HTML dan CSS. Kalau HTML merupakan struktur dari web sedangkan CSS merupakan tampilan dari web maka JS berperan pada keterinteraktifan dalam sebuah web. JavaScript masuk dalam kategori bahasa script yaitu bahasa yang tidak perlu dikompilasi untuk dijalankan. Agar mesin mengerti dari bahasa JavaScript maka digunakan interpreter. Dengan demikian JavaScript termasuk dalam bahasa tingkat tinggi.
Awalnya bahasa pemrograman ini bernama Mocha, kemudian berganti menjadi LiveScript dan berakhir menjadi JavaScript. Bahasa ini pertama kali dikembangkan pada tahun 1995 oleh Brendan Eich. Standarisasi dalam penggunaan JavaScript mengikuti ECMAScript. Bahasa pemrograman untuk website standar biasanya menggunakan JavaScript atau C++ atau PHP. Kelebihan dari JavaScript adalah serbaguna, cukup mudah bagi pemula serta memiliki komunitas yang besar seperti stack overflow yang dapat digunakan untuk berbagi masalah terkait pemrogramannya.
JavaScript ini awalnya hanya bisa dijalankan di environment browser seperti mozilla, safari, dan chrome. Kemudian di tahun 2009 Ryan Dahl menciptakan nodejs, jadi yang tadinya javascript hanya bisa berjalan di browser kemudian diperluas menjadi dapat dijalankan di komputer. Nodejs merupakan engine yang memungkinkan JavaScript digunakan di komputer dan bukan hanya di browser. Dengan demikian JavaScript menjadi bahasa yang sifatnya server side. Sebelumnya diketahui bahwa server side itu seperti java dan kotlin. Sekarang sudah ada alternatif selain nodejs, yaitu deno dan bun.
Ada 4 karakteristik dari JavaScript yaitu yang pertama scripting language interpreted dan bukan compiled (errornya baru ketahuan saat aplikasi dijalankan), kedua case sensitive (huruf kecil dan kapital berbeda), yang ketiga weakly type language (let age=1; age="satu"), dan yang keempat automatically type casting, perhatikan:
- 4 + "4" = "44"
- 4 * "4" = 16
- 2 + true = 3
- if (1) -> true
Sedangkan opsi menjalankan JavaScript ada dua, yaitu:
- Melalui browser (misalnya chrome)
- klik kanan > inspect > console
- Melalui runtime (misalnya node.js)
- instalasi
- official
- install melalui download terlebih dahulu di websitenya
- nvm
- download nvm-setup.zip di https://github.com/coreybutler/nvm-windows/releases/tag/1.1.9
- ekstrak nvm
- install nvm
- jalankan di command prompt dengan syntax nvm
- untuk melihat versi node.js yang bisa diinstal gunakan syntax: nvm list available
- untuk install node.js gunakan syntax: nvm install <versi>
- misalnya install versi 18.5.0 maka: nvm install 18.5.0
- untuk melihat versi apa yang sudah diinstall gunakan syntax: nvm list
- untuk memilih versi yang akan digunakan gunakan syntax: nvm use <versi>
- untuk mengecek versi yang sedang digunakan gunakan syntax: nvm -v
- jalankan secara REPL (read-evaluation-print-looping) melalui cmd dengan syntax: node
- jalankan secara terminal VS code melalui cmd dengan syntax: code .
Ada 3 jenis deklarasi dalam JavaScript yaitu var, let, dan const. Di ES6 deklarasi yang menggunakan var tidak direkomendasikan, sebagai gantinya direkomendasikan melakukan deklarasi dengan menggunakan let dan const. Secara sederhana const atau constant digunakan untuk mendeklarasikan sesuatu yang pasti seperti angka misalnya. Sedikitnya ada 7 tipe data yang biasa digunakan di JavaScript, yaitu:
- Undefined : nilainya tidak ada inisialisasi atau tidak terdefinisi atau tidak jelas
- Numbers : mencakup nilai dari -(253 - 1) hingga (253 - 1)
- BigInt : lebih besar dari number yang biasanya digunakan untuk keperluan kriptografi, caranya menambahkan n pada akhir angka
- Strings : berupa teks
- Boolean : nilai benar atau salah
- Null : nilai sementara pada variabel yaitu 'tidak ada'
- Symbol : jika nama atau deskripsi sama tetap dianggap berbeda, biasanya digunakan di properti objek
Statement atau pernyataan ada 2 jenis yaitu yang non-looping dan looping. Pernyataan yang bersifat non-looping biasanya digunakan untuk berinteraksi dengan client secara tidak berulang, misalnya client menjawab tidak kemudian server akan memberi jawaban benar. Berbeda pada pernyataan looping yang akan melakukan pengulangan pernyataan beberapa kali sesuai kebutuhan. Misalnya akan dilakukan pengecekan berapa huruf a dari kata perserikatan maka perlu dilakukan looping setiap hurup yang ada pada kata perserikatan untuk mengecek berapa jumlah huruf a. Perlu diperhatikan dalam melakukan looping adalah kondisi saat membuat logika yang bersifat infinite.
Di JavaScript conditional statement ada 2, yaitu dengan if else dan switch case. Masing-masing memiliki kelebihan, pada if lese memiliki kelebihan bisa memeroses seluruh tipe data, namun lebih lambat jika dibandingkan switch case. Sedangkan switch case memiliki kelebihan dalam hal kecepatan, namun hanya dapat memeroses tipe data integer atau karakter saja. Looping statement di JavaScript sedikitnya ada 4 cara, yaitu for, for of, while, dan do-while. Cara for of lebih sederhana dibandingkan cara for. Sedangkan cara do-while biasanya digunakan untuk melakukan looping saat input dari client tidak memenuhi syarat. Hal yang perlu dihindari dalam melakukan looping adalah infinite looping atau endless loop. Jika hal tersebut terjadi di cloud computing, tentu itu akan membuat tidak efisien bahkan menyebabkan biaya yang membengkak.
Biasanya tipe data dibedakan menjadi 2 jenis, yaitu tipe data primitif dan tipe data non-primitif. Yang dimaksud tipe data primitif adalah sebuah variabel yang hanya mampu menyimpan satu tipe data, misalnya tipe data number, artinya hanya dapat menyimpan data dalam bentuk number. Dengan demikian yang dimaksud tipe data non-primitif adalah tipe data yang dapat menyimpan beberapa tipe data, misalnya object, yang dapat menyimpan data string dan number secara sekaligus. Tipe data non-primitif adalah:
- Object : menggunakan nama variabel dan kurung kurawal {}, diakses dengan menggunakan dot (.) atau bracket ([...])
- Array : menggunakan indeks dan kurung siku []
- Spread Operator : digunakan untuk menyebarkan array dengan menambah titik tiga ...
- Map : kalau di object pada bagian key hanya mengijinkan tipe data string atau symbol, sedangkan di map bisa digunakan tipe data apapun (jadi ingat di sini key), tetapi pembacaan key dan value tetap secara berurut dari kiri ke kanan misalnya ["Jakarta", "Indonesia"], Jakarta menjadi key dan Indonesia menjadi value
- Metode get() : mendapatkan nilai dengan key tertentu
- Metode set() : menambah pasangan key-value baru
- Set : data tidak berurutan dan tidak berindeks hanya saja ketika ada data yang duplikat maka akan dihapus sehingga hanya ada data tunggal
- Funsi add() : untuk menambah data di dalam set
- const restaurant = {
- "name" : "Joko",
- "city" : "Tangerang",
- "favorite drink" : "Kopi",
- "favorite food" : "Bebek",
- "isVegan" : false
- };
- let name = restaurant.name
- let favoriteDrink = restaurant["favorite drink"]
- let evenNumber = []
- for(let i=1; i<101; i++){
- if((i%2)==0){
- evenNumber.push(i)
- }
- }
- console.log(evenNumber)
- const priceInJPY = 5000;
- const currency = new Map([
- ["USD", 14000],
- ["JPY", 131],
- ["SGD", 11000],
- ["MYR", 3500]
- ]);
- const priceInIDR = currency.get("JPY")*priceInJPY
- console.log(priceInIDR)
Perlu diingat bahwa dalam pengindeksan di JavaScript dimulai dari 0 sehingga jika kita hendak mengambil data ke 7 misalnya maka kita akan menggunakan indeks ke 6. Penerapan dari tipe data, operator, hingga logika akan banyak dilakukan dalam sebuah fungsi. Fungsi atau function ini bisa dianalogikan seperti sebuah mesin. Mesin ini akan dimasukkan bahan mentah dan akan melakukan pemrosesan bahan mentah tersebut sehingga dapat menghasilkan produk, atau secara sederhana input masuk ke dalam fungsi, kemudian fungsi melakukan proses, dan akan menghasilkan output.
Dalam membuat fungsi akan ada 2 istilah penting, yaitu parameter dan argumen. Parameter itu semacam inputnya atau bahan yang akan diolah dalam fungsi, sedangkan argumen ini merupakan bagian proses yang akan menerima input dan menghasilkan output. Agar sebuah fungsi dapat mengembalikan nilai maka perlu ditambahkan syntax return. Yang dimaknai sebagai argument adalah sum(...numbers) pada function di bawah. Parameter ini ada 2 tipe, yaitu parameter yang terbatas dan parameter yang tidak terbatas. Khusus pada parameter yang tidak terbatas ini akan digunakan rest parameter atau spread operator. Contoh penerapan dari rest operator:
- function sum(...numbers) {
- let result = 0;
- for (let number of numbers) {
- result += number;
- }
- return result;
- }
- console.log(sum(1, 2, 3, 4, 5));
Perhatikan contoh di atas, input ada 5 jenis, dan input ini bisa ditambahi dan dikurangi. Terkait fungsi yang berjalan maka ada waktu yang dibutuhkan. Karena adanya tuntutan efisiensi sehingga terciptalah arrow function yang lebih ringkas dibandingkan dengan regular function. Terkadang dalam pembuatan function akan terjadi perubahan yang tidak diharapkan, salah satu yang dapat menyebabkan hal itu adalah adanya scope variable yaitu variabel global dan lokal. Variabel global akan menutupi variabel lokal, oleh sebab itu perlu diperhatikan pengguanan variabel seperti var, let, const, dan tanpa variabel.
Selain ada scope variabel yang perlu dipahami adapula closure yang dapat dimanfaatkan untuk membuat angka bertambah setelahnya. Perhatikan kode di bawah:
- let add = () => {
- let counter = 0;
- return () => {
- return ++counter;
- };
- }
- let addCounter = add();
- console.log(addCounter());
- console.log(addCounter());
- console.log(addCounter());
Output dari kode di atas secara berurut ke bawah akan menjadi 1, 2, 3. Ini tentu bermanfaat saat hendak membuat semacam penomoran. Perhatikan kode di bawah untuk membuat perpangkatan dengan 2 parameter:
- function power(a,b){
- return a**b
- }
- console.log(power(7,3))
Dengan menggunakan function kode akan lebih bersih dan mudah dipahami. Selain itu penggunaan function atau fungsi dapat dilakukan pemanggilan berkali-kali sehingga tidak perlu membuat fungsi satu per satu setiap file yang sebetulnya memiliki fungsi yang sama. Fungsi yang mengembalikan nilai dengan bantuan syntax return dapat disimpan dalam variable, kondisi itu disebut expression function. Dalam melakukan pemrograman bagi seorang developer perlu memiliki pola berpikir OOP atau object oriented programming. Pola pikir tersebut berbasis objek dimana suatu objek terdiri atas kumpulan atribut (menyimpan nilai) dan method (menjalankan proses). Dalam pola pikir OOP ada 4 pilar utama, yaitu:
- Encapsulation
- Attribute atau method di dalam class dibungkus dan bersifat privat sehingga object lain tidak bisa mengakses atau mengubah nilai dari property secara langsung
- Abstraction
- Cukup tahu bagaimana pesan dikirim atau diterima, namun kita tidak perlu tahu seperti apa proses enkripsi dan dekripsi isi pesan, dengan kata lain sebuah objek hanya menunjukkan operasinya secara high-level
- Inheritance
- Beberapa objek bisa memiliki beberapa karakteristik atau perilaku yang sama, tetapi mereka bukanlah objek yang sama, misalnya antara email dan SMS memiliki kesamaan isi konten pesan serta alamat pengirim dan alamat penerima
- Polymorphism
- Objek dapat memiliki bentuk atau implementasi yang berbeda-beda pada satu metode yang sama, misalnya semua jenis Mail dapat mengirim pesan, namun whatsapp, email, sms tentunya memiliki cara yang berbeda dalam mengirim pesan
Dalam OOP dikenal istilah class yaitu kumpulan informasi tentang suatu object. Secara lebih sederhana class ini adalah sebuah template yang digunakan untuk membuat object dalam pengembangan menggunakan JavaScript. Nah, di dalam template tersebut dapat diterapkan beberapa jenis method seperti class method, static method, dan constructor.
Contoh class method (menggunakan metode sendMessage):
- const mail1 = new Mail();
- mail1.sendMessage('hallo', 'penerima@gmail.com');
- /**
- output-nya berhasil:
- you send: hallo to penerima@gmail.com from pengirim@gmail.com
- **/
Contoh static method (menggunakan namaClass.namaMethod()):
- class Mail{
- static isValidPhone(phone) {
- return typeof phone === 'number';
- }
- }
- Mail.isValidPhone(089000000000) //true
Contoh constructor:
- Statement Class
- class Mail {
- constructor(author) {
- this.from = author;
- console.log('is instantiated', author);
- };
- }
- const mail1 = new Mail("emailku@gmail.com");
- Statement Function
- function Mail(author) {
- this.from = author;
- console.log('is instantiated', author);
- }
- const mail1 = new Mail("emailku@gmail.com");
Seperti sebelumnya telah diketahui bahwa ada pilar inheritance atau pewarisan yang dilakukan oleh parent class ke child class. Misalkan telah dimiliki parent class dan kemudian telah ada 2 child class, namun pada satu ketika hendak dibuat child class baru, akan tetapi terjadi beberapa masalah yang kurang sesuai di parent class. Dalam hal ini akan ada 2 jenis keputusan, apakah akan membuat parent class baru atau apakah akan merombak parent class yang telah ada sehingga dapat menampung 3 child class. Tentu yang paling baik jika satu parent class dapat digunakan untuk 3 child class. Oleh karena itu perlu diusahakan melakukan perombakan (tentunya dipertimbangkan kemungkinan sebelumnya). Perombakan baik sebagian atau secara keseluruhan ini disebut overriding. Tujuan dari overriding adalah menyesuaikan behavior yang ada di child class.
Contoh overriding constructor:
- class WhatsApp extends Mail {
- constructor(username, isBussinessAccount, phone) {
- super(phone);
- this.username = username;
- this.isBussinessAccount = isBussinessAccount;
- }
- }
- const wa1 = new WhatsApp('jokourno', true, 089989090898);
Contoh overriding method:
- class WhatsApp extends Mail {
- constructor(username, isBussinessAccount, phone) {
- super(phone);
- this.username = username;
- this.isBussinessAccount = isBussinessAccount;
- }
- // Overriding method => Melakukan Override Total
- sendMessage(msg, to) {
- console.log('Send by WA');
- }
- }
- const wa1 = new WhatsApp('di', true, 089000999888);
- wa1.sendMessage('halo', 089000999888);
- /**
- Output:
- Send by WA
- **/
Agar dapat melakukan eksekusi kode pada parent class maka perlu menggunakan operator super.methodName(). Perhatikan perubahan kode di atas akan menjadi:
- class WhatsApp extends Mail {
- constructor(username, isBussinessAccount, phone) {
- super(phone);
- this.username = username;
- this.isBussinessAccount = isBussinessAccount;
- }
- // Overriding method => Melakukan Override Total
- sendMessage(msg, to) {
- super.sendMessage(msg, to);
- console.log('Send by WA');
- }
- }
- const wa1 = new WhatsApp('di', true, 089000999888);
- wa1.sendMessage('halo', 089000999888);
![]() |
sumber: https://pixabay.com/id/vectors/javascript-js-logo-kode-sumber-736400/ |
OOP atau object oriented programming pada dasarnya akan mempermudah dalam melakukan pembangunan. Nah, untuk pembangunan tersebut secara optimal dibuat sebuah konsep parent class dan child class. Parent class mewarisi karakter yang memungkinkan ada pada child class sehingga bisa lebih sederhana. Mungkin jika terjadi pengurangan child class, tidak perlu dilakukan perombakan parent class akan tetapi jika terjadi penambahan child class tidak jarang akan dilakukan perombakan pada parent class sebagai bentuk penyesuaian behavior dari child class yang ada. Dengan demikian pembangunan perangkat lunak dengan konsep OOP akan membentuk hierarki seperti gambar di atas.
Walaupun sah melakukan perombakan parent class karena adanya child class, namun terkadang waktu yang dibutuhkan untuk melakukan perombakan cukup lama, apalagi ketika menemui masalah yang cukup kompleks. Untuk menghemat waktu bisa digunakan pendekatan object composition yaitu prinsip komposisi tanpa perlu melakukan pewarisan dari parent class. Perhatikan kode di bawah:
- // [1] list of abstractions
- const canSendMessage = self => ({
- sendMessage: () => console.log('send message:', self.message)
- });
- const checkIsValidPhone = self => ({
- isValid: () => console.log('valid phone', self.from)
- });
- // [2] create object composition
- const personalEnterprise = (from, message, store) => {
- // [3] attributes
- const self = {
- from,
- message,
- store
- };
- // [4] method
- const personalEnterpriseBehaviors = self => ({
- createCatalog: () => console.log('Catalog has created: ', self.store)
- });
- // [5] create object composition
- return Object.assign(self, personalEnterpriseBehaviors(self), canSendMessage(self), checkIsValidPhone(self));
- };
- const pe1 = personalEnterprise('pengirim@gmail.com', 'hei produk baru nih', 'App Store');
- pe1.createCatalog(); //Catalog has created: App Store
- pe1.sendMessage(); //send message: hei produk baru nih
Di dalam JavaScript juga ada built-in class bawaan yang dapat digunakan untuk mempermudah pengembangan perangkat lunak. Maksud dari built-in class adalah sebuah kode yang terkandung dalam syntax untuk tujuan tertentu, misalnya untuk menampilkan tanggal hari ini tidak perlu melakukan koding dari awal sehingga cukup menggunakan built-in class seperti const myDate = new Date();. Daftar method yang umum digunakan:
- getMonth(), getFullYear(), getDate(), getHours(), getMinutes(), getSeconds(), getMilliseconds(), getTime(), dan getDay()
- Cara penggunaan:
- const myDate = new Date();
- console.log(myDate.getDay())
- //hasilnya berupa angka sehingga jika ingin diubah perlu menggunakan static method
Contoh penggunaan built-in class:
- // parameter birthday dapat berupa miliseconds ataupun date string
- const myAge = birthday => {
- const birtday = new Date(birthday);
- const today = Date.now(); // today menghasilkan nilai miliseconds saat ini
- const diff_ms = today - birtday.getTime(); // menghitung selisih nilai miliseconds hari ini dan tanggal lahir
- const diffDate = new Date(diff_ms);
- return diffDate.getFullYear() - 1970; // 1970 adalah representasi 0 dari miliseconds
- };
- console.log(myAge('2000-01-22')); // 22 tahun
Contoh pembuatan class, turunan, dan instance:
- class Animal {
- constructor (name, age, isMammal) {
- this.name = name;
- this.age = age;
- this.isMammal = isMammal;
- }
- }
- class Rabbit extends Animal {
- constructor(name, age) {
- super(name, age, true);
- }
- eat() {
- return `${this.name} sedang makan!`;
- }
- }
- class Eagle extends Animal {
- constructor(name, age) {
- super(name, age, false);
- }
- fly() {
- return `${this.name} sedang terbang!`;
- }
- }
- let myRabbit = new Rabbit("Labi", 2)
- let myEagle = new Eagle("Elo", 4)
- console.log(Animal)
- console.log(Rabbit)
- console.log(Eagle)
- console.log(myRabbit)
- console.log(myEagle)
Selain OOP atau object oriented programming sebagai pola pikir lain dikenal pula functional programming atau FP. Pola pikir FP lebih cenderung ke 'what to solve' dibandingkan 'how to solve' sehingga FP memiliki gaya deklaratif dibandingkan imperatif. Perbedaan dari gaya deklaratif dan imperatif tentu pada kode yang ditulis. Pada gaya deklaratif kode cenderung lebih singkat namun lebih lebih abstrak dibanding dengan gaya deklaratif yang seakan diketahui bagaimana input itu diproses. Perhatikan perbandingan kode di bawah:
- Kode imperatif
- const names = ['Harry', 'Ron', 'Jeff', 'Thomas'];
- const newNamesWithExcMark = [];
- for(let i = 0; i < names.length; i++) {
- newNamesWithExcMark.push(`${names[i]}!`);
- }
- console.log(newNamesWithExcMark);
- /* output:
- [ 'Harry!', 'Ron!', 'Jeff!', 'Thomas!' ]
- */
- Kode deklaratif
- const names = ['Harry', 'Ron', 'Jeff', 'Thomas'];
- const newNamesWithExcMark = names.map((name) => `${name}!`);
- console.log(newNamesWithExcMark);
- /* output:
- * [ 'Harry!', 'Ron!', 'Jeff!', 'Thomas!' ]
- */
Ada 4 konsep yang diusung oleh FP, yaitu:
- Pure Function
- Fungsi tidak boleh bergantung dengan nilai luar serta tidak boleh mengubah nilai yang berada di luar baik sengaja maupun tidak sengaja, misalnya nilai phi yang dibuat variabel padahal bisa langsung ditulis dalam fungsi angkanya
- Immutability
- Objek tidak berubah setelah memasuki fungsi, misalnya objeknya 'aku' setelah memasuki fungsi berubah menjadi 'aku!'
- Rekursif
- Teknik pada sebuah fungsi yang memanggil dirinya sendiri
- Contoh kode awal:
- const countDown = start => {
- do {
- console.log(start);
- start -=1;
- }
- while(start > 0);
- };
- countDown(10);
- Perubahan menjadi rekursif
- const countDown = start => {
- console.log(start);
- if(start > 0) countDown(start-1);
- };
- countDown(10);
- Higher-Order Function
- Fungsi dapat menerima fungsi lainnya pada argumen atau mengembalikannya
Apabila konsep dari FP atau functional programming dijalankan secara baik dan benar maka fungsi yang dihasilkan akan menjadi fungsi yang reuseable atau bisa digunakan berkali-kali tanpa perlu khawatir terjadinya perubahan yang diluar dugaan. Ada beberapa reuseable function yang telah disediakan oleh JavaScript seperti yang dimiliki array yaitu map, filter, dan foreach.
Array map biasa digunakan untuk menghasilkan array baru. Perhatikan contoh kode di bawah:
- const newArray = ['Harry', 'Ron', 'Jeff', 'Thomas'].map((name) => { return `${name}!`});
- console.log(newArray);
- /**
- * [ 'Harry!', 'Ron!', 'Jeff!', 'Thomas!' ]
- *
- */
Array filter biasa digunakan untuk menghasilkan array hasil saringan tertentu. Perhatikan contoh kode di bawah:
- const students = [
- {
- name: 'Harry',
- score: 60,
- },
- {
- name: 'James',
- score: 88,
- },
- {
- name: 'Ron',
- score: 90,
- },
- {
- name: 'Bethy',
- score: 75,
- }
- ];
- const eligibleForScholarshipStudents = students.filter((student) => student.score > 85);
- console.log(eligibleForScholarshipStudents);
- /**
- * output:
- * [ { name: 'James', score: 88 }, { name: 'Ron', score: 90 } ]
- *
- */
Array reduce biasa digunakan untuk menghasilkan satu nilai output, misalnya penjumlahan. Perhatikan kode di bawah:
- const students = [
- {
- name: 'Harry',
- score: 60,
- },
- {
- name: 'James',
- score: 88,
- },
- {
- name: 'Ron',
- score: 90,
- },
- {
- name: 'Bethy',
- score: 75,
- }
- ];
- const totalScore = students.reduce((acc, student) => acc + student.score, 0);
- console.log(totalScore);
- /**
- * output:
- * 313
- *
- */
Array some biasa digunakan untuk mengetahui kondisi dalam sebuah array dengan hasil boolean. Perhatikan kode di bawah:
- const array = [1, 2, 3, 4, 5];
- const even = array.some(element => element % 2 === 0);
- console.log(even);
- /**
- output true
- **/
Array find biasa digunakan untuk menemukan sebuah kondisi yang ada dalam array. Perhatikan kode di bawah:
- const students = [
- {
- name: 'Harry',
- score: 60,
- },
- {
- name: 'James',
- score: 88,
- },
- {
- name: 'Ron',
- score: 90,
- },
- {
- name: 'Bethy',
- score: 75,
- }
- ];
- const findJames = students.find(student => student.name === 'James');
- console.log(findJames);
- /**
- output
- { name: 'James', score: 88 }
- **/
Array sort biasa digunakan untuk mengurutkan nilai pada array. Perhatikan kode di bawah:
- const months = ['March', 'Jan', 'Feb', 'Dec'];
- months.sort();
- console.log(months);
- // output: [ 'Dec', 'Feb', 'Jan', 'March' ]
- const array1 = [1, 30, 4, 1000, 101, 121];
- array1.sort();
- console.log(array1);
- // output: [ 1, 1000, 101, 121, 30, 4 ]
Array every biasa digunakan untuk memeriksa apakah seluruh array yang ada sesuai kriteria, hasilnya berupa nilai boolean. Perhatikan kode di bawah:
- const scores = [70,85,90];
- const minimumScore = 65;
- const examPassed = scores.every(score => score >= minimumScore);
- console.log(examPassed);
- /**
- output
- true
- **/
Array forEach biasa digunakan untuk memanggil fungsi callback pada setiap iterasi. Perhatikan kode di bawah:
- const names = ['Harry', 'Ron', 'Jeff', 'Thomas'];
- names.forEach((name) => {
- console.log(`Hello, ${name}!`);
- });
- /**
- * output:
- * Hello, Harry!
- * Hello, Ron!
- * Hello, Jeff!
- * Hello, Thomas!
- *
- */
Sekarang perhatikan penerapan filter dan map pada koding di bawah:
- const books = [
- { title: 'The Da Vinci Code', author: 'Dan Brown', sales: 5094805 },
- { title: 'The Ghost', author: 'Robert Harris', sales: 807311 },
- { title: 'White Teeth', author: 'Zadie Smith', sales: 815586 },
- { title: 'Fifty Shades of Grey', author: 'E. L. James', sales: 3758936 },
- { title: 'Jamie\'s Italy', author: 'Jamie Oliver', sales: 906968 },
- { title: 'I Can Make You Thin', author: 'Paul McKenna', sales: 905086 },
- { title: 'Harry Potter and the Deathly Hallows', author: 'J.K Rowling', sales: 4475152 },
- ];
- const greatAuthors = books.filter ((books)=> books.sales > 1000000 ).map((books) => {return `${books.author} adalah penulis buku ${books.title} yang sangat hebat!`})
- console.log(greatAuthors)
Bahasan di atas adalah dasar-dasar dari penggunakan bahasa pemrograman JavaScript. Untuk dapat mengaplikasikannya secara langsung diperlukan environment seperti text editor, terminal, dan node.js. Kelebihan dari implementasi node.js diantaranya seperti asynchronous atau tidak memblokir proses lain saat menunggu satu proses selesai. Node.js bisa didownload di: https://nodejs.org/. Untuk instalasi di windows ikuti prosesnya secara default saja. Jika menggunakan linux maka gunakan syntax:
- curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
- jika error maka harus di downloa curl terlebih dahulu dengan syntax
- sudo apt-get install curl
- sudo apt-get install -y nodejs
- Tunggu hingga selesai, untuk memastikan node.js telah terintal maka gunakan syntax:
- node -v
- npm -v
Sekarang peralatan untuk melakukan pengembangan web berbasis JavaScript telah siap. Buka text editor kemudian arahkan ke folder yang dijadikan penyimpanan dokumen web, kemudian gunakan syntax:
- npm init
- Nanti akan muncul pertanyaan terkait project yang akan dibuat
- node index.js
- Digunakan untuk menjalankan file JavaScript yang telah diketik kode
- npm run test
- Digunakan untuk menjalankan script pada projek
- Sebelumnya dibuat kode:
- "scripts": {
- "test": "echo \"Error: no test specified\" && exit 1",
- "start": "node index.js"
- },
Sampai di sini telah diketahui dasar-dasar pemrograman JavaScript dan penerapannya melalui text editor. Nah, sebuah perangkat lunak atau dalam hal ini web akan memiliki baris kode yang bergantung dari fitur yang hendak disajikan oleh web tersebut. Semakin kaya fitur dari web maka akan semakin banyak juga kode yang dibuat. Sayangnya terkadang akan terjadi bug atau kode tidak berjalan sesuai yang diharapkan, bayangkan jika kode yang ditulis berjumlah ribuan atau jutaan maka perlu diperiksa untuk memperbaiki bug tersebut. Oleh karena itu dilakukan pemisahan beberapa bagian dari file JavaScript dengan tujuan mempermudah dalam melakukan perbaikan bug. Karena ada bagian yang terpisah maka perlu dibuat modul, modul itu digunakan untuk menghubungkan berkas JavaScript yang saling terpisah.
Secara sederhana modul bekerja dengan cara exporting dan importing. Perhatikan kode yang akan dijadikan exporting (nama filenya state.js):
- const coffeeStock = {
- arabica: 100,
- robusta: 150,
- liberica: 200
- };
- module.exports = coffeeStock;
Cara importing gunakan kode di bawah (nama filenya index.js):
- const coffeeStock = require('./state');
- console.log(coffeeStock);
- /* output
- { arabica: 100, robusta: 150, liberica: 200 }
- */
Pada baris pertama kode di file index.js itu ada require('./state'), maksud dari kode ini adalah mencari file state.js. Ada saatnya perlu untuk melakukan exporting 2 atau lebih variabel maka syntax-nya agak sedikit berubah menjadi (menggunakan literal {}):
- module.exports = {coffeeStock, isCoffeeMachineReady};
- Untuk ekspornya
- const {coffeeStock, isCoffeeMachineReady} = require('./state');
- Untuk impornya
Nah, pada ES6 module saat melakukan import lebih mudah dipahami secara visual, karena menggunakan syntax:
- import coffeeStock from "./state.js";
- untuk import satu object
- import { coffeeStock, isCoffeeMachineReady } from './state.js';
- untuk import 2 object
- import { coffeeStock as stock, isCoffeeMachineReady } from './state.js';
- untuk import object yang diganti namanya, jadi dari object coffeeStock menjadi stock, sehingga untuk menampilkannya bukan console.log(coffeeStock) melainkan console.log(stock)
Dengan adanya module akan membuat pemrograman lebih terstruktur dan lebih mudah menemukan error yang terjadi. Sekarang pertanyaannya, bagaimana cara menyelesaikan error yang terjadi pada kode JavaScript yang telah dibuat. Sebelum menyelesaikan error maka perlu diketahui lebih dahulu mengapa terjadi error, nah, untuk mengetahui error apa yang sedang terjadi dapat digunakan kode try dan catch. Dengan catch bisa ditampilkan name, message, dan stack dari error yang terjadi pada kode. Perhatikan pemeriksaan error pada kode di bawah:
- try {
- console.log("Awal blok try"); // (1)
- errorCode; // (2)
- console.log("Akhir blok try"); // (3)
- } catch (error) {
- console.log(error.name);
- console.log(error.message);
- console.log(error.stack);
- }
- /* output
- Awal blok try
- ReferenceError
- errorCode is not defined
- ReferenceError: errorCode is not defined
- at file:///home/jokourno/Playground/javascript/CoffeeMachine/error.js:3:5
- at ModuleJob.run (internal/modules/esm/module_job.js:152:23)
- at async Loader.import (internal/modules/esm/loader.js:166:24)
- at async Object.loadESM (internal/process/esm_loader.js:68:5)
- */
Perhatikan kode untuk menemukan informasi error di bawah:
- class ValidationError extends Error {
- constructor(message) {
- super(message);
- this.name = "ValidationError";
- }
- }
- let json = '{ "age": 30 }';
- try {
- let user = JSON.parse(json);
- if (!user.name) {
- throw new ValidationError("'name' is required.");
- }
- if (!user.age) {
- throw new ValidationError("'age' is required.");
- }
- console.log(user.name);
- console.log(user.age);
- } catch (error) {
- if (error instanceof SyntaxError) {
- console.log(`JSON Syntax Error: ${error.message}`);
- } else if (error instanceof ValidationError) {
- console.log(`Invalid data: ${error.message}`);
- } else if (error instanceof ReferenceError) {
- console.log(error.message);
- } else {
- console.log(error.stack);
- }
- }
- /* output
- Invalid data: 'name' is required.
- */
Perhatikan penerapan try dan catch pada kode di bawah:
- // TODO 1
- class ValidationError extends Error {
- constructor(message) {
- super(message);
- this.name = "ValidationError";
- }
- }
- // TODO 2
- function validateNumberInput (a,b,c) {
- if(typeof(a) !== 'number'){
- throw new ValidationError("Argumen pertama harus number");
- }
- if(typeof(b) !== 'number'){
- throw new ValidationError("Argumen kedua harus number");
- }
- if(typeof(c) !== 'number'){
- throw new ValidationError("Argumen ketiga harus number");
- }
- }
- const detectTriangle = (a, b, c) => {
- // TODO 3
- try{
- validateNumberInput(a,b,c)
- }
- catch(error){
- return error.message
- }
- if (a === b && b === c) {
- return 'Segitiga sama sisi';
- }
- if (a === b || a === c || b === c) {
- return 'Segitiga sama kaki';
- }
- return 'Segitiga sembarang';
- };
Sampai di sini sudah cukup lengkap pembahasan dari pemrograman menggunakan JavaScript, yaitu dasar pemrogramannya, penerapan melalui editor, dan menangani error yang terjadi. Satu topik yang menarik yaitu concurrency atau beberapa komputasi yang terjadi pada saat yang bersamaan. Berjalannya kode itu ada 2 jenis, yaitu sinkron dan asinkron. Kode yang berjalan secara sinkron artinya kode tersebut berjalan mulai dari baris kode teratas, jika kode tersebut berhasil tereksekusi maka berlanjut ke kode yang ada di bawahnya, dan jika kode tersebut tidak berhasil tereksekusi maka kode setelahnya juga tidak akan tereksekusi. Sedangkan pada asinkron kode yang akan dieksekusi lebih dulu tidak bergantung pada letak barisnya.
Coba jalankan kode di bawah dengan menggunakan text editor:
- console.log("Selamat datang!");
- setTimeout(() => {console.log("Terima kasih sudah mampir, silakan datang kembali!");}, 3000);
- console.log("Ada yang bisa dibantu?");
Kode di atas akan mengeksekusi baris ke 3 lebih dulu dibandingkan baris ke 2. Ini membuktikan bahwa JavaScript dapat bekerja secara asinkron. Terkadang akan sedikit mengganggu ketika bekerja dengan kode yang berjalan secara sinkron dan asinkron, oleh sebab itu ada yang disebut callback function. Coba jalankan kode di bawah dan perhatikan cara kerjanya:
- const orderCoffee = callback => {
- let coffee = null;
- console.log("Sedang membuat kopi, silakan tunggu...");
- setTimeout(() => {
- coffee = "Kopi sudah jadi!";
- callback(coffee);
- }, 3000);
- }
- orderCoffee(coffee => {
- console.log(coffee);
- });
Nah, kode di atas hanya berhubungan dengan 2 kalimat, bagaimana jika hubungan ini terjadi pada banyak kalimat. Kondisi itu disebut dengan callback hell. Jika tetap diusahakan dengan callback maka itu akan memakan waktu yang lumayan, oleh sebab itu tersedia kode promise yang mengandung 3 kondisi, yaitu pending, fulfilled, dan rejected. Dalam praktikya, Promise biasa digunakan untuk menjalankan proses asynchronous seperti mengambil data dari internet/API.
Tahap penerapan dari promise pertama adalah membuat object promise, kedua mengonsumsi promise. Perhatikan kode yang membangun object promise di bawah:
- const executorFunction = (resolve, reject) => {
- const isCoffeeMakerReady = true;
- if (isCoffeeMakerReady) {
- resolve("Kopi berhasil dibuat");
- } else {
- reject("Mesin kopi tidak bisa digunakan");
- }
- }
- const makeCoffee = () => {
- return new Promise(executorFunction);
- }
- const coffeePromise = makeCoffee();
- console.log(coffeePromise);
- /* output
- Promise { 'Kopi berhasil dibuat' }
- */
Jika nilai isCoffeeMakerReady diubah menjadi false maka outputnya akan menjadi Promise {"Mesin kopi tidak bisa digunakan"}. Jadi kemungkinan output dari promise ada 2, yaitu fulfilled dan rejected. Nah, hasil dari promise tersebut ditangani dengan method .then(). Perhatikan cara menangani hasil dari promise pada kode di bawah:
- const stock = {
- coffeeBeans: 250,
- water: 1000,
- }
- const checkStock = () => {
- return new Promise((resolve, reject) => {
- if (stock.coffeeBeans >= 16 && stock.water >= 250) {
- resolve("Stok cukup. Bisa membuat kopi");
- } else {
- reject("Stok tidak cukup");
- }
- });
- };
- const handleSuccess = resolvedValue => {
- console.log(resolvedValue);
- }
- const handleFailure = rejectionReason => {
- console.log(rejectionReason);
- }
- checkStock().then(handleSuccess, handleFailure);
Sejauh ini kode yang dibuat sudah cukup kompleks. Kode yang kompleks ini menandakan fitur yang dapat disajikan akan lebih kaya. Namun, pada sisi lain semakin kompleks kode yang ada maka akan sedikit lebih sulit juga menangani jika terjadi kegagalan dalam kode yang berjalan. Sehingga diperlukan sebuah prinsip separation of concerns atau pemisahan masalah. Yang dimaksud pemisahan masalah di sini adalah mengorganisasi kode ke dalam bagian-bagian yang berbeda berdasarkan tujuannya. Perlu dicatat pemisahan masalah ini maksudnya lebih detail dibandingkan pembagian pada module exporting dan importing. Dalam hal ini yang dimaksud adalah perbedaan kode yang membuat lebih mudah mendeteksi adanya masalah.
Perhatikan konsumsi kode promise di bawah:
- checkStock()
- .then(handleSuccess)
- .then(null, handleFailure);
Bandingkan dengan kode:
- checkStock()
- .then(handleSuccess)
- .catch(handleFailure);
Kedua kode di atas sama-sama memiliki 2 kondisi, yaitu saat berhasil dan saat gagal. Namun, pada kode pertama sama-sama menggunakan .then(), sedangkan pada kode kedua digunakan dua kode .then() dan .catch(). Perbedaan kode pada kode kedua ini yang disebut sebagai separation of concerns. Nah, untuk mempermudah menemukan terjadinya masalah pada kode yang kompleks sebaiknya diperhatikan juga menggunakan kode yang berbeda pada masalah yang bercabang. Walaupun promise memiliki 2 output utama namun ada masalah yang sifatnya berantai dan diselesaikan dengan promise untuk menghindari callback hell. Perhatikan kode di bawah:
- const state = {
- stock: {
- coffeeBeans: 250,
- water: 1000,
- },
- isCoffeeMachineBusy: false,
- }
- const checkAvailability = () => {
- return new Promise((resolve, reject) => {
- setTimeout(() => {
- if (!state.isCoffeeMachineBusy) {
- resolve("Mesin kopi siap digunakan.");
- } else {
- reject("Maaf, mesin sedang sibuk.");
- }
- }, 1000);
- });
- };
- const checkStock = () => {
- return new Promise((resolve, reject) => {
- state.isCoffeeMachineBusy = true;
- setTimeout(() => {
- if (state.stock.coffeeBeans >= 16 && state.stock.water >= 250) {
- resolve("Stok cukup. Bisa membuat kopi.");
- } else {
- reject("Stok tidak cukup!");
- }
- }, 1500);
- });
- };
- const brewCoffee = () => {
- console.log("Membuatkan kopi Anda...")
- return new Promise((resolve, reject) => {
- setTimeout(() => {
- resolve("Kopi sudah siap!")
- }, 2000);
- });
- };
- function makeEspresso() {
- checkAvailability()
- .then((value) => {
- console.log(value);
- return checkStock();
- })
- .then((value) => {
- console.log(value)
- return brewCoffee();
- })
- .then(value => {
- console.log(value);
- state.isCoffeeMachineBusy = false;
- })
- .catch(rejectedReason => {
- console.log(rejectedReason);
- state.isCoffeeMachineBusy = false;
- });
- }
- makeEspresso();
- /* output
- Mesin kopi siap digunakan.
- Stok cukup. Bisa membuat kopi.
- Membuatkan kopi Anda...
- Kopi sudah siap!
- */
Pada kode di atas promise dibuat secara sendiri, lalu bagaimana jika akan dieksekusi promise lebih dari satu secara bersamaan. Jawabannya adalah promise.all(). Perhatikan cara menerapkannya pada kode di bawah:
- const promises = [firstPromise(), secondPromise(), thirdPromise()];
- Promise.all(promises)
- .then(resolvedValue => {
- console.log(resolvedValue);
- });
- /* output
- [ 'first promise', 'second promise', 'third promise' ]
- */
Seseorang yang biasa bekerja dengan gaya kode sinkron maka akan sedikit perlu adaptasi saat bekerja dengan gaya asinkron. Namun, jika memang tetap hendak tidak mengilangkan gaya sinkron tetapi memerlukan kode asinkron maka dapat digunakan syntax async-await. Perhatikan penggunaan kode di bawah:
- async function makeCoffee() {
- const coffee = await getCoffee();
- console.log(coffee);
- }
- makeCoffee();
- /* output
- Kopi didapatkan!
- */
Selain untuk menangani error, try dan catch juga diterapkan untuk menangani rejected pada promise, perhatikan kode di bawah:
- async function makeCoffee() {
- try {
- const coffee = await getCoffee();
- console.log(coffee);
- } catch (rejectedReason) {
- console.log(rejectedReason);
- }
- }
- makeCoffee();
- /* output
- Biji kopi habis!
- */
Perhatikan kode di bawah untuk melakukan penerapan async-await pada promise yang berantai:
- async function makeEspresso() {
- try {
- await checkAvailability();
- await checkStock();
- const coffee = await brewCoffee();
- console.log(coffee);
- } catch (rejectedReason) {
- console.log(rejectedReason);
- }
- }
- makeEspresso();
- /* output
- Membuatkan kopi Anda...
- Kopi sudah siap!
- */
Dan penerapan async-await pada promise.all:
- async function makeEspresso() {
- try {
- await checkAvailability();
- await checkStock();
- await Promise.all([boilWater(), grindCoffeeBeans()]);
- const coffee = await brewCoffee();
- console.log(coffee);
- } catch (rejectedReason) {
- console.log(rejectedReason);
- }
- }
Agar lebih memahami perhatikan penerapan async-await di bawah:
- class NetworkError extends Error {
- constructor(message) {
- super(message);
- this.name = 'NetworkError';
- }
- }
- // TODO: 1
- const fetchingUserFromInternet = (isOffline) => {
- return new Promise((resolve, reject) => {
- setTimeout(() => {
- if (isOffline) {
- reject(new NetworkError('Gagal mendapatkan data dari internet'));
- }
- resolve({ name: 'John', age: 18 });
- }, 500);
- })
- };
- TODO: 2
- //Cara tanpa async-await
- //const gettingUserName = () => {
- // return fetchingUserFromInternet(false)
- // .then(user => user.name)
- // .catch(error => error.message)
- //};
- //Cara dengan async-await
- const gettingUserName = async () => {
- try {
- const user = await fetchingUserFromInternet(false);
- return user.name;
- } catch (error) {
- return error.message;
- }
- };
Sekarang sudah semakin lengkap pemahaman tentang pemrograman JavaScript, yaitu dasar pemrogramannya, penerapan melalui editor, menangani error yang terjadi, dan pemahaman tentang sinkron-asinkron. Sudah cukup bekal awal untuk menjelajahi JavaScript. Nah, dalam pembuatan kode, tidak seluruh kode dibuat secara mandiri, ada kode-kode tertentu yang sudah disediakan, semacam library yang langsung pakai. Library ini disebut dengan package. Misalnya untuk menampilkan kalender, tidak perlu dilakukan pembuatan koding secara mandiri jika koding kalender sudah tersedia di package JavaScript.
Kalau di bahasa Java ada maven dan grandle, di PHP ada composer, di python ada pip, maka di JavaScript ada yang disebut NPM atau node package manager. NPM secara lengkap ada di : https://www.npmjs.com/. Ikuti instruksinya untuk instalasi. Secara detail command yang ada di NPM dapat dilihat dengan syntax: npm help di command prompt. Sebelum melakukan instalasi package maka perlu dipastikan dalam folder projek itu sudah ada file package.json, jika file tersebut belum ada maka dapat dibuat dengan syntax: npm init. File ini bertujuan untuk memberi informasi package apa yang telah terinstal di projek yang berjalan.
Ada 2 objek dalam file package.json, yaitu object dependencies (untuk membuat aplikasi) dan object devdependencies (hanya dalam proses pembuatan aplikasi). Setelah package terinstal maka cara menggunakan package tersebut mirip dengan penggunaan modul. Gunakan syntax seperti contohnya:
- import _ from 'lodash';
Syntax di atas diketik pada berkas kode JavaScript. Untuk menggunakan sebuah package perlu dilihat dokumentasi dari package tersebut. Sedangkan saat hendak menguninstal sebuah package perhatikan contoh syntax berikut (syntax di bawah diketik di command prompt):
- npm uninstall lodash
Lengkap sudah bekal dari bekal memahami pemprograman JavaScript, yaitu dasar pemrogramannya, penerapan melalui editor, menangani error yang terjadi, pemahaman tentang sinkron-asinkron, dan penggunaan package. Dengan kelimanya sudah bisa dibuat sebuah perangkat lunak yang dikehendaki. Namun, setelah perangkat lunak tersebut dibuat tentu perlu dilakukan uji untuk memastikan bahwa perangkat lunak yang dibangun betul-betul sudah layak disampaikan kepada pengguna. Pengujian perangkat lunak terbagi menjadi 2, yaitu otomatis (komputasi) dan manual (digunakan secara langsung).
Objek pengujian biasanya seperti memastikan tidak ada typo (static test), setiap unit kode berjalan dengan baik (unit test), memastikan beberapa rangkaian fungsi yang saling tergantung berjalan (integration test), dan pengujian dari awal hingga akhir fungsional perangkat lunak (end-to-end test). Biasanya sebelum melakukan pengujian perlu ditanyakan apa yang akan diuji dan apa harapan yang didefinisikan. Langkah dalam melakukan testing:
- Membuat proyek baru dengan direktori bernama latihantesting
- Masuk ke dalam direktori latihantesting dan gunakan syntax: npm init
- Install library framework jest dengan syntax: npm install --save-dev jest
- Setelah proses instalasi selesai, buka proyek di code editor
- Pada file package.json, kita tambahkan script untuk test, perhatikan:
- {
- "scripts": {
- "test": "jest"
- }
- }
- Perhatikan kode di bawah:
- test('deskripsi dari testcase kamu', () => {
- expect(perintah).matcher(nilai yang diekspektasikan);
- });
- // contoh
- test('dua tambah dua adalah empat', () => {
- expect(2+2).toBe(4);
- });
- Detail dapat dilihat di: https://jestjs.io/docs/using-matchers
- Misalnya file gradeCalculations.js, letakkan file tersebut di folder: __tests__
- Perhatikan kode di bawah:
- const { averageExams } = require('../gradeCalculations');
- test('it should return exact average', () => {
- const listValueOfExams = [80, 100, 100, 80];
- expect(averageExams(listValueOfExams)).toEqual(90);
- })
- Jalankan kode dengan syntax: npm run test
- Setelah melakukan semua test case yang ada bisa dilihat laporan kode yang sudah dilakukan pengujian dengan syntax: npm run test -- --coverage
ref: