Bab 3: Object-Oriented Programming dalam JavaScript

Bab 3: Object-Oriented Programming dalam JavaScript

3.1 Konsep Dasar OOP

3.1.1 Pengenalan OOP

  • Definisi Object-Oriented Programming

  • Keuntungan menggunakan OOP

  • Perbedaan OOP dengan functional programming

  • Use cases untuk OOP dalam JavaScript

3.1.2 Empat Pilar OOP

/*
1. Encapsulation: Membungkus data dan method yang memanipulasi data dalam satu unit
2. Inheritance: Mewarisi properties dan methods dari class lain
3. Polymorphism: Kemampuan object untuk mengambil berbagai bentuk
4. Abstraction: Menyembunyikan kompleksitas dan hanya menunjukkan fungsionalitas yang diperlukan
*/

3.2 Constructor dan Class

3.2.1 Constructor Functions (Pre-ES6)

// Constructor function
function Person(name, age) {
    this.name = name;
    this.age = age;
    
    this.greet = function() {
        return `Hello, I'm ${this.name}`;
    };
}

// Creating instances
const person1 = new Person("John", 30);
const person2 = new Person("Jane", 25);

console.log(person1.greet()); // "Hello, I'm John"

3.2.2 ES6 Class Syntax

class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    
    greet() {
        return `Hello, I'm ${this.name}`;
    }
    
    // Static method
    static createAnonymous() {
        return new Person("Anonymous", 0);
    }
    
    // Getter
    get info() {
        return `${this.name} is ${this.age} years old`;
    }
    
    // Setter
    set info(value) {
        [this.name, this.age] = value.split(' ');
    }
}

3.3 Inheritance

3.3.1 Prototypal Inheritance

// Base constructor
function Animal(name) {
    this.name = name;
}

Animal.prototype.makeSound = function() {
    console.log("Some sound");
};

// Inheriting constructor
function Dog(name, breed) {
    Animal.call(this, name);
    this.breed = breed;
}

// Setting up inheritance
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

// Adding method to Dog
Dog.prototype.bark = function() {
    console.log("Woof!");
};

3.3.2 Class Inheritance (ES6)

class Animal {
    constructor(name) {
        this.name = name;
    }
    
    makeSound() {
        console.log("Some sound");
    }
}

class Dog extends Animal {
    constructor(name, breed) {
        super(name);
        this.breed = breed;
    }
    
    bark() {
        console.log("Woof!");
    }
}

const myDog = new Dog("Rex", "German Shepherd");
myDog.makeSound(); // Inherited method
myDog.bark();     // Own method

3.4 Encapsulation

3.4.1 Private Fields dan Methods (ES2022)

class BankAccount {
    #balance = 0; // Private field
    
    constructor(initialBalance) {
        this.#balance = initialBalance;
    }
    
    #validateAmount(amount) { // Private method
        return amount > 0 && amount <= this.#balance;
    }
    
    withdraw(amount) {
        if (this.#validateAmount(amount)) {
            this.#balance -= amount;
            return true;
        }
        return false;
    }
    
    getBalance() {
        return this.#balance;
    }
}

3.4.2 Closure untuk Private Data

function createCounter() {
    let count = 0; // Private variable
    
    return {
        increment() {
            count++;
            return count;
        },
        decrement() {
            count--;
            return count;
        },
        getCount() {
            return count;
        }
    };
}

const counter = createCounter();

3.5 Polymorphism

3.5.1 Method Overriding

class Shape {
    calculateArea() {
        return 0;
    }
}

class Circle extends Shape {
    constructor(radius) {
        super();
        this.radius = radius;
    }
    
    calculateArea() {
        return Math.PI * this.radius ** 2;
    }
}

class Rectangle extends Shape {
    constructor(width, height) {
        super();
        this.width = width;
        this.height = height;
    }
    
    calculateArea() {
        return this.width * this.height;
    }
}

3.5.2 Interface-like Behavior

class DataStorage {
    save(data) {
        throw new Error("Method 'save' must be implemented");
    }
    
    load() {
        throw new Error("Method 'load' must be implemented");
    }
}

class FileStorage extends DataStorage {
    save(data) {
        console.log("Saving to file:", data);
    }
    
    load() {
        return "Data from file";
    }
}

class DatabaseStorage extends DataStorage {
    save(data) {
        console.log("Saving to database:", data);
    }
    
    load() {
        return "Data from database";
    }
}

3.6 Prototype dan Prototype Chain

3.6.1 Understanding Prototypes

function Student(name) {
    this.name = name;
}

Student.prototype.study = function() {
    console.log(`${this.name} is studying`);
};

const student1 = new Student("Alice");

console.log(student1.__proto__ === Student.prototype); // true
console.log(Student.prototype.__proto__ === Object.prototype); // true

3.6.2 Prototype Methods dan Properties

// Adding methods to built-in objects (not recommended in production)
Array.prototype.sum = function() {
    return this.reduce((a, b) => a + b, 0);
};

const numbers = [1, 2, 3, 4];
console.log(numbers.sum()); // 10

3.7 Design Patterns

3.7.1 Singleton Pattern

class Singleton {
    static #instance;
    
    constructor() {
        if (Singleton.#instance) {
            return Singleton.#instance;
        }
        Singleton.#instance = this;
    }
    
    static getInstance() {
        if (!Singleton.#instance) {
            Singleton.#instance = new Singleton();
        }
        return Singleton.#instance;
    }
}

3.7.2 Factory Pattern

class Vehicle {
    constructor(type, model) {
        this.type = type;
        this.model = model;
    }
}

class VehicleFactory {
    createVehicle(type, model) {
        switch(type) {
            case 'car':
                return new Car(model);
            case 'truck':
                return new Truck(model);
            default:
                throw new Error('Unknown vehicle type');
        }
    }
}

3.8 Praktik dan Latihan

3.8.1 Project: Library Management System

class Book {
    #isbn;
    constructor(title, author, isbn) {
        this.title = title;
        this.author = author;
        this.#isbn = isbn;
    }
}

class Library {
    #books = new Map();
    
    addBook(book) {
        // Implementation
    }
    
    removeBook(isbn) {
        // Implementation
    }
    
    findBook(isbn) {
        // Implementation
    }
}

3.8.2 Project: Shopping Cart System

class Product {
    constructor(id, name, price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }
}

class ShoppingCart {
    #items = new Map();
    
    addItem(product, quantity) {
        // Implementation
    }
    
    removeItem(productId) {
        // Implementation
    }
    
    calculateTotal() {
        // Implementation
    }
}

3.9 Best Practices dan Common Pitfalls

  • Avoiding global scope pollution

  • Proper use of 'this'

  • When to use inheritance vs composition

  • Performance considerations

  • Memory management

  • Error handling in OOP

3.10 Ringkasan

  • OOP fundamentals in JavaScript

  • Modern vs traditional approaches

  • Design patterns dan use cases

  • Best practices dan pitfalls

3.11 Latihan Akhir Bab

  1. Implement a bank account system

  2. Create a school management system

  3. Build a simple game using OOP

  4. Implement common design patterns

  5. Refactor functional code to OOP

Last updated