0
0
Lập trình
Admin Team
Admin Teamtechmely

Hiểu Về Lập Trình Hướng Đối Tượng (OOP) Trong JavaScript

Đăng vào 5 tháng trước

• 8 phút đọc

Giới thiệu

Lập trình giống như việc xây dựng một thành phố. Bạn không chỉ đơn giản là ném gạch, xi măng và kim loại lại với nhau một cách ngẫu nhiên, mà bạn cần tổ chức chúng một cách cẩn thận thành các cấu trúc như nhà cửa, trường học và bệnh viện. Tương tự, lập trình cũng cần có cấu trúc và tổ chức để làm cho các chương trình dễ dàng xây dựng, mở rộng và bảo trì.

Đây chính là lúc Lập trình Hướng Đối Tượng (OOP) xuất hiện. OOP là một mô hình lập trình cho phép các nhà phát triển mô hình hóa các thực thể trong thế giới thực dưới dạng các đối tượng với các thuộc tính (dữ liệu) và hành vi (hàm). Trong JavaScript, OOP rất mạnh mẽ vì nó giúp mã của bạn có thể tái sử dụng, mở rộng và dễ hiểu hơn.

Hiểu rõ OOP trong JavaScript là rất quan trọng vì nó cung cấp cho bạn nền tảng để làm việc trên các dự án phức tạp, hợp tác với các nhóm và viết mã sạch, mô-đun phản ánh các tình huống thực tế.

Trong hướng dẫn này, chúng tôi sẽ đơn giản hóa khái niệm Lập trình Hướng Đối Tượng (OOP) và làm cho nó dễ hiểu cho người học ở mọi cấp độ. Đến cuối hướng dẫn này, độc giả không chỉ nắm vững các nguyên tắc cơ bản của OOP mà còn có thể tự tin áp dụng chúng trong việc xây dựng cả dự án đơn giản và phức tạp.

OOP là gì?

Lập trình Hướng Đối Tượng (OOP) là một cách viết mã nơi bạn cấu trúc nó xung quanh các đối tượng. Một đối tượng là một tập hợp các thuộc tính (thuộc tính) và phương thức (hàm) mô tả và kiểm soát một thứ cụ thể. JavaScript, khác với một số ngôn ngữ OOP truyền thống như Java hoặc C++, dựa trên prototype, nhưng với sự ra đời của ES6, chúng ta đã có cú pháp class giúp OOP trong JavaScript trở nên quen thuộc và dễ đọc hơn.

Các nguyên tắc cốt lõi của OOP trong JavaScript

Có bốn trụ cột chính của OOP. Hãy cùng phân tích chúng:

  1. Đóng gói (Encapsulation): Kết hợp dữ liệu và phương thức liên quan trong một đối tượng duy nhất trong khi hạn chế truy cập trực tiếp vào một số phần nhất định.

  2. Trừu tượng (Abstraction): Ẩn chi tiết phức tạp và chỉ hiển thị những điều thiết yếu.

  3. Kế thừa (Inheritance): Cho phép một lớp (con) nhận các thuộc tính và phương thức của một lớp khác (cha).

  4. Đa hình (Polymorphism): Khả năng của cùng một phương thức hoặc hàm hành xử khác nhau tùy thuộc vào ngữ cảnh.

Phân tích tương tự trong thế giới thực về OOP

Hãy tưởng tượng bạn đang thiết kế một Hệ thống Xe ô tô:
Đóng gói: Xe có các thuộc tính như màu sắc, thương hiệu, và kiểu động cơ, và các phương thức như startEngine() hoặc applyBrakes(). Bạn không kiểm soát cách động cơ hoạt động bên trong, bạn chỉ cần khởi động nó.
Trừu tượng: Bạn điều khiển vô lăng để thay đổi hướng nhưng bạn không cần biết về vật lý phức tạp phía sau điều đó.
Kế thừa: Một Xe Thể Thao có thể nhận các tính năng của một Xe Ô Tô chung nhưng có thêm các tính năng như turboBoost().
Đa hình: Phương thức drive() có thể có nghĩa khác nhau tùy thuộc vào liệu đó là Xe Ô Tô, Xe Đạp, hay Xe Tải.

Cấu trúc này giúp hệ thống xe ô tô dễ hiểu, mở rộng và bảo trì. Điều tương tự cũng áp dụng cho mã.

OOP trong JavaScript với ví dụ

  1. Đóng gói (Tạo một lớp) Đóng gói có nghĩa là kết hợp dữ liệu (thuộc tính) và phương thức (hàm) thành một đơn vị (lớp).
javascript Copy
// Ví dụ về Đóng gói với lớp Car
class Car {
  // Constructor được sử dụng để khởi tạo các thuộc tính của đối tượng
  constructor(brand, color) {
    this.brand = brand; // thuộc tính lưu thương hiệu xe
    this.color = color; // thuộc tính lưu màu xe
  }

  // Phương thức để khởi động động cơ xe
  startEngine() {
    // Truy cập thuộc tính thương hiệu của xe
    console.log(`${this.brand} động cơ đã khởi động!`);
  }
}

// Tạo một đối tượng mới (instance) của lớp Car
const myCar = new Car("Toyota", "Red");

// Gọi phương thức để khởi động động cơ
myCar.startEngine(); // Kết quả: Toyota động cơ đã khởi động!
  1. Trừu tượng
    Trừu tượng ẩn các chi tiết không cần thiết và chỉ hiển thị các phương thức thiết yếu.
javascript Copy
// Ví dụ về Trừu tượng với lớp BankAccount
class BankAccount {
  constructor(owner, balance) {
    this.owner = owner; // tên chủ tài khoản

    // Biến riêng để giữ số dư
    // Nó không thể được truy cập trực tiếp bên ngoài lớp
    let _balance = balance;

    // Phương thức để kiểm tra số dư hiện tại (truy cập kiểm soát)
    this.getBalance = function() {
      return _balance;
    };

    // Phương thức để gửi tiền (thay đổi số dư bên trong)
    this.deposit = function(amount) {
      _balance += amount;
      console.log(`Đã gửi ${amount}. Số dư mới: ${_balance}`);
    };
  }
}

// Tạo một tài khoản ngân hàng mới với số dư ban đầu là 1000
const account = new BankAccount("Peace", 1000);

// Gửi tiền bằng phương thức đã cung cấp
account.deposit(500); // Kết quả: Đã gửi 500. Số dư mới: 1500

// Truy cập số dư một cách an toàn thông qua phương thức
console.log(account.getBalance()); // Kết quả: 1500

// Truy cập trực tiếp như account._balance là không thể (đã ẩn!)
  1. Kế thừa
    Kế thừa cho phép một lớp nhận các thuộc tính và phương thức của lớp khác.
javascript Copy
// Lớp cha Vehicle
class Vehicle {
  constructor(type) {
    this.type = type; // loại phương tiện (ví dụ: Xe Ô Tô, Xe Đạp, Xe Tải)
  }

  // Phương thức để di chuyển
  move() {
    console.log(`${this.type} đang di chuyển...`);
  }
}

// Lớp con Bike mở rộng từ Vehicle
class Bike extends Vehicle {
  constructor(type, brand) {
    // super() gọi constructor của lớp cha
    super(type);
    this.brand = brand; // thương hiệu của xe đạp
  }

  // Ghi đè phương thức move() của lớp cha với hành vi tùy chỉnh
  move() {
    console.log(`${this.brand} ${this.type} đang tăng tốc!`);
  }
}

// Tạo một instance của Bike
const myBike = new Bike("Xe Máy", "Yamaha");

// Gọi phương thức đã ghi đè
myBike.move(); // Kết quả: Yamaha Xe Máy đang tăng tốc!
  1. Đa hình
    Đa hình cho phép cùng một tên phương thức hành xử khác nhau tùy thuộc vào đối tượng.
javascript Copy
// Lớp cha Animal
class Animal {
  // Phương thức mặc định cho tiếng nói
  speak() {
    console.log("Con vật này phát ra âm thanh.");
  }
}

// Lớp con Dog ghi đè speak()
class Dog extends Animal {
  speak() {
    console.log("Gâu! Gâu!");
  }
}

// Lớp con Cat ghi đè speak()
class Cat extends Animal {
  speak() {
    console.log("Meo!");
  }
}

// Tạo một mảng các động vật khác nhau
const animals = [new Dog(), new Cat(), new Animal()];

// Mỗi đối tượng phản ứng khác nhau với cùng một cuộc gọi phương thức
animals.forEach(animal => animal.speak());

/* Kết quả:
Gâu! Gâu!
Meo!
Con vật này phát ra âm thanh.
*/

Tầm quan trọng của OOP trong JavaScript

1. Tái sử dụng mã
• Với OOP, bạn có thể tạo ra các lớp hoặc đối tượng có thể tái sử dụng được sử dụng ở nhiều phần khác nhau của ứng dụng.
• Ví dụ: Một lớp User với các phương thức đăng nhập/đăng xuất có thể được sử dụng lại trong nhiều dự án khác nhau.
2. Tính mô-đun (Tổ chức tốt hơn)
• OOP giúp chia nhỏ mã phức tạp thành các phần nhỏ hơn, dễ quản lý (lớp/đối tượng).
• Mỗi đối tượng tập trung vào một nhiệm vụ cụ thể, giúp mã nguồn dễ dàng điều hướng và bảo trì hơn.
3. Đóng gói (Ẩn dữ liệu & Bảo mật)
• OOP cho phép bạn ẩn các chi tiết triển khai bên trong của một đối tượng và chỉ hiển thị những gì cần thiết.
• Ví dụ: Thay vì thay đổi trực tiếp số dư của tài khoản ngân hàng, bạn có thể chỉ cho phép gửi/rút tiền thông qua các phương thức cụ thể.
4. Kế thừa (Tránh trùng lặp)
• Bạn có thể tạo ra một lớp cha với các thuộc tính và phương thức chung và để các lớp con kế thừa chúng.
• Điều này giảm thiểu việc trùng lặp mã và đảm bảo tính nhất quán.
• Ví dụ: Một lớp Vehicle → được mở rộng bởi Car, Bike, Bus.
5. Đa hình (Tính linh hoạt & Mở rộng)
• Các đối tượng có thể chia sẻ cùng một giao diện nhưng hành xử khác nhau dựa trên ngữ cảnh.
• Ví dụ: Một phương thức draw() có thể vẽ một hình tròn, hình vuông hoặc hình tam giác khác nhau tùy thuộc vào đối tượng.
6. Cải thiện khả năng bảo trì
• Vì OOP cấu trúc mã của bạn thành các đối tượng rõ ràng và tự chứa, việc sửa lỗi, thêm tính năng hoặc thay đổi mà không làm hỏng các phần khác trở nên dễ dàng hơn.

7. Khả năng mở rộng (Tốt cho các ứng dụng lớn)
• Các dự án lớn (như ứng dụng web, trò chơi, và phần mềm doanh nghiệp) hưởng lợi từ OOP vì nó giúp dễ dàng quản lý các mã nguồn ngày càng phát triển.
8. Mô hình hóa thế giới thực
• OOP phản ánh các thực thể trong thế giới thực (người dùng, sản phẩm, đơn hàng, v.v.), giúp thiết kế trở nên trực quan hơn.
• Ví dụ: Trong một ứng dụng thương mại điện tử, bạn có thể có các lớp cho Product, Cart và Order tương tự như các đối tượng trong thế giới thực.

Kết luận

Lập trình Hướng Đối Tượng (OOP) trong JavaScript không chỉ là một khái niệm — đó là một cách mạnh mẽ để suy nghĩ về mã. Bằng cách hiểu rõ về đóng gói, trừu tượng, kế thừa và đa hình, bạn có thể viết các chương trình sạch sẽ, thông minh và chuyên nghiệp hơn.
OOP giống như các khối xây dựng — một khi bạn nắm vững chúng, bạn có thể tạo ra những ứng dụng từ nhỏ như máy tính đến lớn như một nền tảng mạng xã hội.

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào