Pemrogramman Berbasis Object di Javascript

Pengenalan Pemrograman Berorientasi Objek (OOP)

Perbedaan Procedural dan Object Oriented

Dalam dunia pemrogramman, ada yang disebut dengan Paradigma Pemrogramman. Paradigma pemrograman adalah sebuah filosofi yang mendasari cara programmer berpikir dan menulis kode. Paradigma ini menentukan bagaimana program disusun, bagaimana data diorganisir, dan bagaimana program berinteraksi dengan pengguna. Dua jenis paradigma yang umum dijumpai adalah Procedural Programming dan Object Oriented Programming (OOP).

Analoginya, Procedural Programming bagaikan mengikuti langkah-langkah dalam sebuah resep atau panduan. Setiap langkah terhubung dengan langkah sebelumnya, membentuk urutan instruksi yang terstruktur. Pendekatan ini cocok untuk project kecil dan sederhana, di mana program didefinisikan sebagai kumpulan prosedur yang berurutan.
function hitungTotalNilai(nilaiArr) {
  let total = nilaiArr.reduce((total, nilai) => total + nilai, 0);
  return total;
}

function hitungRataRata(nilai) {
  const totalNilai = hitungTotalNilai(nilai);
  const jumlahNilai = nilai.length;
  const rataRata = totalNilai / jumlahNilai;
  return rataRata;
}

const nilaiUjian = [80, 75, 90, 85, 95];
const totalNilai = hitungTotalNilai(nilaiUjian);
const rataRataNilai = hitungRataRata(nilaiUjian);

console.log(`Total nilai ujian: ${totalNilai}`);
console.log(`Rata-rata nilai ujian: ${rataRataNilai}`);  

Sedangkan OOP berfokus pada `Object`, yakni sebuah entitas atau benda yang memiliki data (property) dan kemampuan (method). OOP bagaikan merancang sebuah blueprint atau skema untuk membuat objek tersebut.
class Mahasiswa {
  constructor(nama, nilai) {
    this.nama = nama;
    this.nilai = nilai;
  }

  hitungTotalNilai() {
    let total = this.nilai.reduce((total, nilai) => total + nilai, 0);
    return total;
  }

  hitungRataRata() {
    const totalNilai = this.hitungTotalNilai();
    const jumlahNilai = this.nilai.length;
    const rataRata = totalNilai / jumlahNilai;
    return rataRata;
  }

  displayMessage() {
    console.log(`Nama: ${this.nama}`);
    console.log(`Total Nilai: ${this.hitungTotalNilai()}`);
    console.log(`Rata-rata Nilai: ${this.hitungRataRata()}`);
  }
}

const mahasiswa1 = new Mahasiswa("Budi", [80, 75, 90]);
const mahasiswa2 = new Mahasiswa("Ani", [85, 95, 90]);
mahasiswa1.displayMessage();
mahasiswa2.displayMessage();


Dasar-Dasar Pemrograman Berorientasi Objek

Object dalam Javascript

Struktur Object Javascript

Object ibarat wadah yang berisi berbagai informasi tentang suatu entitas atau benda. Object memiliki property (seperti nama, warna, bentuk) untuk menyimpan data tentang object tersebut, dan method (function yang ada di dalam object) yang memungkinkan object untuk melakukan tindakan.
const mobil = {
    name: "Toyota Avanza", // Property
    max_kecepatan: 120, // Property
    kecepatan: 0, // Property

    tambahKecepatan: function (num) { // Method
        if (this.kecepatan + num > this.max_kecepatan) {
            return 'Melebihi maximum kecepatan.';
        }
        this.kecepatan += num;
        return this.kecepatan;
    },
    
    kurangiKecepatan: function (num) { // Method
        if (this.kecepatan - num < 0) {
            return 'Kecepatan tidak boleh negatif.';
        }
        this.kecepatan -= num;
        return this.kecepatan;
    }
};

console.log(mobil.kecepatan);
console.log(mobil.tambahKecepatan(45));
console.log(mobil.kurangiKecepatan(20));

Dalam object di Javascript, terdapat keyword this yang memiliki fungsi merujuk kepada object yang sedang dieksekusi. Secara sederhana, property dalam object bisa diibaratkan seperti variable, untuk mengakses property tersebut kita gunakan keyword this. Contohnya pada bagian this.kecepatan merujuk kepada property kecepatan dalam object tersebut.

Membuat Object Menggunakan Class

Visualisasi Class

Ketika kita ingin membuat object dengan struktur yang sama berulang kali, dua pendekatan utama dapat digunakan adalah membuat Function Constructor atau Class.

Function Constructor merupakan cara lama untuk membuat object di Javascript. Cara ini berfokus pada function yang mengembalikan object baru dengan struktur yang telah ditentukan.
function Mobil(name, max_kecepatan) {
    this.name = name,
    this.max_kecepatan = max_kecepatan;
    this.kecepatan = 0;

    this.tambahKecepatan = (num) => {
        if (this.kecepatan + num > this.max_kecepatan) {
            return 'Melebihi maximum kecepatan.';
        }
        this.kecepatan += num;
        return this.kecepatan;
    }

    this.kurangiKecepatan = (num) => {
        if (this.kecepatan - num < 0) {
            return 'Kecepatan tidak boleh negatif.';
        }
        this.kecepatan -= num;
        return this.kecepatan;
    }
}

const Mobil_Toyota = new Mobil("Toyota Avanza", 120);
console.log(Mobil_Toyota.tambahKecepatan(130));
console.log(Mobil_Toyota.kurangiKecepatan(19));

const Mobil_Tesla = new Mobil("Tesla Model S", 115);
console.log(Mobil_Tesla.tambahKecepatan(40));
console.log(Mobil_Tesla.kurangiKecepatan(20));

Pada Javascript versi ES6, diperkenalkan fitur Class untuk membuat sebuah object dengan sintaks yang lebih ringkas. Di dalam class terdapat method constructor untuk mendefinisikan property dalam object tersebut
class Mobil {
    constructor(name, max_kecepatan) {
        this.name = name,
        this.max_kecepatan = max_kecepatan;
        this.kecepatan = 0;
    }

    tambahKecepatan = (num) => {
        if (this.kecepatan + num > this.max_kecepatan) {
            return 'Melebihi maximum kecepatan.';
        }
        this.kecepatan += num;
        return this.kecepatan;
    }

    kurangiKecepatan = (num) => {
        if (this.kecepatan - num < 0) {
            return 'Kecepatan tidak boleh negatif.';
        }
        this.kecepatan -= num;
        return this.kecepatan;
    }
}

const Mobil_Wuling = new Mobil("Wuling Confero S", 185);
console.log(Mobil_Wuling.name);
console.log(Mobil_Wuling.max_kecepatan);
console.log(Mobil_Wuling.tambahKecepatan(185));
console.log(Mobil_Wuling.kurangiKecepatan(50));


Konsep Lanjutan Pemrograman Berorientasi Objek

Inheritance

Visualisasi Inheritance

Inheritance (Pewarisan) adalah mekanisme di mana suatu class dapat mewarisi properti dan method dari class lain. Class yang mewarisi properti dan method dari class lain disebut subclass (class turunan), sedangkan class yang diwarisi disebut superclass atau parent class (class induk).
// Parent class (superclass)
class Animal {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }

    eat(food) {
        console.log(`${this.name} is eating ${food}.`);
    }

    sleep(hours) {
        console.log(`${this.name} is sleeping for ${hours} hours.`);
    }
}

// Subclass 1
class Bird extends Animal {
    constructor(name, age, species) {
        super(name, age);
        this.species = species;
    }

    fly(distance) {
        console.log(`${this.name} has flown a distance of ${distance} meters`);
    }
}

// Subclass 2
class Cat extends Animal {
    constructor(name, age, color) {
        super(name, age);
        this.color = color;
    }

    walk(distance) {
        console.log(`${this.name} has walked a distance of ${distance} meters`);
    }

    meow() {
        console.log(`${this.name} is meowing.`);
    }
}

const myBird = new Bird("Kenari", 3, "canary");
const myCat = new Cat("Oren", 2, "orange");

myBird.fly(200);
myCat.meow();
myCat.walk(3141592653589);

Berikut penjelasan mengenai kata kunci konsep Inheritance di Javascript:
  • extends : Digunakan untuk membuat subclass dari superclass.
  • super : Digunakan dalam method constructor subclass yang berfungsi mengambil property dan method dari superclass.
  • this : Dalam konteks Inheritance, this digunakan untuk mengakses properti dan method dari superclass maupun subclass.

Polymorphism

Visualisasi Polymorphism

Polymorphism adalah kemampuan yang memungkinkan objek untuk menunjukkan perilaku yang berbeda tergantung pada konteksnya. Hal ini sering terjadi dalam hubungan Inheritance, di mana class turunan (subclass) mewarisi method dengan nama yang sama dari class induknya (superclass), tetapi perilaku method tersebut dapat diubah sesuai dengan kebutuhan dalam implementasi class turunannya.
class Shape {
    constructor(name) {
        this.name = name;
    }

    // Base Method
    getArea() {
        console.log("Area calculation not implemented for base Shape class!");
    }
}

class Square extends Shape {
    constructor(name, side) {
        super(name);
        this.side = side;
    }

    // Override method
    getArea() {
        return this.side * this.side;
    }
}

class Circle extends Shape {
    constructor(name, radius) {
        super(name);
        this.radius = radius;
    }

    // Override method
    getArea() {
        return Math.PI * this.radius * this.radius;
    }
}

function calculateArea(shape) {
    console.log(shape.getArea());
}

let mySquare = new Square("Square", 5);
let myCircle = new Circle("Circle", 3);

calculateArea(mySquare);
calculateArea(myCircle);

Encapsulation

Visualisasi Encapsulation

Encapsulation adalah konsep dalam OOP yang berfungsi menyembunyikan detail implementasi internal suatu class. Ini artinya pengguna class (programmer lain) tidak perlu tahu cara data disimpan di dalamnya. Interaksi dengan data di dalam class dapat dilakukan melalui method yang bersifat public yang telah dirancang dengan baik, seperti setter untuk merubah data dan getter untuk mengambil data. Hal ini bertujuan untuk mencegah manipulasi langsung terhadap data sensitif.

Konsep utama dalam Encapsulation adalah Access Modifier yakni konsep untuk menentukan hak akses terhadap data atau method di dalam class. Terdapat tiga jenis access modifier yakni:
  • Public : Data bisa diakses dari dalam class maupun luar class.
  • Private : Data hanya bisa diakses dari dalam class tersebut.
  • Protected : Data hanya bisa diakses dari dalam class tersebut dan class turunannya (sub-class).

Javascript tidak sepenuhnya mendukung konsep Access Modifier. Secara default, semua data dalam class secara otomatis memiliki access modifier public dan untuk membuatnya private atau protected menggunakan tanda `_` tetapi ini hanya kebiasaan yang disepakati beberapa programmer. Namun pada Javascript versi ES2022, fitur access modifier private atau  bisa digunakan dengan menambahkan tanda `#` pada property atau method.
class BankAccount {
    #accountID; // Private Property
    #ownerName; // Private Property
    _balance; // Protected Property

    constructor(ownerName) {
        this.#accountID = crypto.randomUUID();
        this.#ownerName = ownerName;
        this._balance = 0;
    }

    getAccountID() {
        return this.#accountID;
    }

    getOwnerName() {
        return this.#ownerName;
    }

    getBalance() {
        return this._balance;
    }

    setOwnerName(newOwnerName) {
        this.#ownerName = newOwnerName;
    }

    deposit(amount) {
        this._balance += amount;
        console.log(`Deposit of $${amount} successful. New balance: $${this._balance}`);
    }

    withdraw(amount) {
        if (amount > this._balance) {
            console.log("Insufficient funds.");
        } else {
            this._balance -= amount;
            console.log(`Withdrawal of $${amount} successful. New balance: $${this._balance}`);
        }
    }
}

class SavingsAccount extends BankAccount {
    #interestRate; // Private Property

    constructor(ownerName, interestRate) {
        super(ownerName);
        this.#interestRate = interestRate;
    }

    #calculateInterest() { // Private Method
        const interest = this._balance * this.#interestRate;
        return interest;
    }

    addMonthlyInterest() {
        const earnedInterest = this.#calculateInterest();
        this._balance += earnedInterest;
        console.log(`New balance after adding interest: $${this._balance}`);
    }

    getBalance() {
        return this._balance + this.#calculateInterest();
    }
}

// Usage example
// Bank Account
const JohnSmith_BankAccount = new BankAccount("John Smith");
JohnSmith_BankAccount.deposit(1250);
JohnSmith_BankAccount.withdraw(500);
console.log("Account ID:", JohnSmith_BankAccount.getAccountID());
console.log("Current Balance:", JohnSmith_BankAccount.getBalance());

// Savings Account
const Sucipto_SavingsAccount = new SavingsAccount("Sucipto", 0.03);
Sucipto_SavingsAccount.deposit(6000);
Sucipto_SavingsAccount.addMonthlyInterest();
console.log("Account ID:", Sucipto_SavingsAccount.getAccountID());
console.log("Current Balance:", Sucipto_SavingsAccount.getBalance());

// Set New Name
const Maulana_SavingsAccount = new SavingsAccount("Maulana", 0.07);
console.log("Original Owner Name:", Maulana_SavingsAccount.getOwnerName());
Maulana_SavingsAccount.setOwnerName("Prof. Maulana S.Kom");
console.log("Updated Owner Name:", Maulana_SavingsAccount.getOwnerName()); 

Typescript, bahasa pemrograman turunan Javascript, secara native mendukung konsep OOP seperti access modifier. Kode Javascript di atas dapat ditulis ulang dengan Typescript sebagai berikut:
class BankAccount {
    private accountID: string;
    private ownerName: string;
    protected balance: number;

    constructor(ownerName: string) {
        this.accountID = crypto.randomUUID();
        this.ownerName = ownerName;
        this.balance = 0;
    }

    getAccountID(): string {
        return this.accountID;
    }

    getOwnerName(): string {
        return this.ownerName;
    }

    getBalance(): number {
        return this.balance;
    }

    setOwnerName(newOwnerName: string): void {
        this.ownerName = newOwnerName;
    }

    deposit(amount: number): void {
        this.balance += amount;
        console.log(`Deposit of $${amount} successful. New balance: $${this.balance}`);
    }

    withdraw(amount: number): void {
        if (amount > this.balance) {
            console.log("Insufficient funds.");
        } else {
            this.balance -= amount;
            console.log(`Withdrawal of $${amount} successful. New balance: $${this.balance}`);
        }
    }
}

class SavingsAccount extends BankAccount {
    private interestRate: number;

    constructor(ownerName: string, interestRate: number) {
        super(ownerName);
        this.interestRate = interestRate;
    }

    private calculateInterest(): number {
        const interest = this.balance * this.interestRate;
        return interest;
    }

    addMonthlyInterest(): void {
        const earnedInterest = this.calculateInterest();
        this.balance += earnedInterest;
        console.log(`New balance after adding interest: $${this.balance}`);
    }

    getBalance(): number {
        return this.balance + this.calculateInterest();
    }
}

// Usage example
// Bank Account
const JohnSmith_BankAccount = new BankAccount("John Smith");
JohnSmith_BankAccount.deposit(1250);
JohnSmith_BankAccount.withdraw(500);
console.log("Account ID:", JohnSmith_BankAccount.getAccountID());
console.log("Current Balance:", JohnSmith_BankAccount.getBalance());

// Savings Account
const Sucipto_SavingsAccount = new SavingsAccount("Sucipto", 0.03);
Sucipto_SavingsAccount.deposit(6000);
Sucipto_SavingsAccount.addMonthlyInterest();
console.log("Account ID:", Sucipto_SavingsAccount.getAccountID());
console.log("Current Balance:", Sucipto_SavingsAccount.getBalance());

// Set New Name
const Maulana_SavingsAccount = new SavingsAccount("Maulana", 0.07);
console.log("Original Owner Name:", Maulana_SavingsAccount.getOwnerName());
Maulana_SavingsAccount.setOwnerName("Prof. Maulana S.Kom");
console.log("Updated Owner Name:", Maulana_SavingsAccount.getOwnerName()); 


Interface

Interface adalah deklarasi kumpulan method yang harus diimplementasikan oleh class. Interface tidak menyediakan implementasi method, melainkan hanya mendefinisikan "kontrak" yang harus dipatuhi oleh class yang mengimplementasikannya. Hal yang dideklarasikan dalam Interface meliputi nama dan tipe data yang dikembalikan (return) dari method tersebut.

Javascript tidak mendukung fitur Interface. Namun, hal ini bisa digantikan dengan Typescript. Keyword implement digunakan untuk mendeklarasikan bahwa suatu class mengimplementasikan interface tertentu.
interface IArticle {
    // Property
    title: string;
    author: string;
    content: string;

    // Methods
    getWordCount(): number;
    getSummary(): string;
    printArticle(): string;
}

class Article implements IArticle {
    public title: string;
    public author: string;
    public content: string;

    constructor(title: string, author: string, content: string) {
        this.title = title;
        this.author = author;
        this.content = content;
    }

    getWordCount(): number {
        return this.content.split(" ").length;
    }

    getSummary(): string {
        const summaryLength = 100;
        return this.content.substring(0, summaryLength) + "...";
    }

    printArticle(): string {
        return `${this.title}\nBy: ${this.author}\n\n${this.content}`;
    }
}

// Usage
let myArticle = new Article(
    "Cara Kolaborasi di Github",
    "John Smith",
    `Pertama, Fork dan clone repository. Kedua, Buat clone repository. Ketiga, Buat branch baru.
     Keempat, Lakukan perubahan. Kelima, Commit dan push. Keenam, Buat pull request.
     Ketujuh, Tunggu review. Kedelapan, Merge.`,
);

console.log(myArticle.getWordCount());
console.log(myArticle.getSummary());
console.log(myArticle.printArticle());


Kelebihan dan Kekurangan Pemrograman Berorientasi Objek di JavaScript

Kelebihan

1. Reusability
Konsep seperti inheritance dan polymorphism membuat kode yang ditulis dalam class dapat digunakan kembali di class turunannya sehingga mengurangi duplikasi kode.

2. Modularity
OOP membantu memecah kode menjadi class-class yang lebih kecil dan terisolasi. Hal ini membuat kode lebih terstruktur, mudah dipahami, dan dikelola.

3. Scalability
OOP memungkinkan pengembangan aplikasi yang scalable karena kemampuannya dalam mengorganisasi dan mengelola kode dengan baik, sehingga mempermudah penambahan fitur dan modifikasi di masa mendatang.

Kekurangan

1. Kurangnya Fitur OOP
Javascript bukanlah bahasa pemrogramman murni berorientasi object seperti Java. Fitur OOP seperti access modifier dan interface tidak didukung secara native.

2. Kompleksitas Kode
Implementasi OOP dalam JavaScript dapat meningkatkan kompleksitas kode, terutama bagi programmer yang tidak terbiasa dengan konsep OOP.

3. Overhead Performa
Mendefinisikan class dan object dalam JavaScript membutuhkan resource tambahan dibandingkan dengan function tradisional. Hal ini berdampak pada performa program, terutama pada perangkat dengan resource terbatas.


Kesimpulan

Pemrograman berorientasi objek (OOP) merupakan paradigma pemrograman yang digunakan untuk membangun aplikasi yang kompleks dan terstruktur. OOP menawarkan konsep seperti encapsulation, inheritance, polymorphism, dan abstraction, yang dapat membantu programmer untuk menulis kode yang lebih modular dan reusable. Namun perlu diperhatikan bahwa Javascript bukanlah bahasa pemrogramman yang secara murni berorientasi object. Ada beberapa fitur OOP yang tidak didukung dalam Javascript tetapi hal ini bisa ditangani menggunakan library atau menggunakan bahasa pemrogramman Typescript.

Apakah paradigma OOP harus digunakan dalam JavaScript? Jawabannya tergantung pada kebutuhan dan kompleksitas projek yang sedang dikerjakan. Untuk projek kecil dan sederhana, Procedural Programming mungkin lebih cocok. Namun, untuk projek yang kompleks, OOP menawarkan fitur bermanfaat yang dapat membantu programmer membangun projek yang lebih maintainable.

Posting Komentar

0 Komentar