Tìm hiểu kế thừa trong JavaScript
Javascript nâng cao | by
Trong lập trình hướng đối tượng, kế thừa (Inheritance) là một khái niệm quan trọng giúp tái sử dụng mã nguồn và mở rộng chức năng của các lớp (class). Trước khi có ES6, JavaScript sử dụng mô hình prototype-based inheritance, nhưng kể từ ES6, việc kế thừa trở nên đơn giản và dễ hiểu hơn với từ khóa extends
.
Kế thừa trong JavaScript cho phép một lớp con (subclass) kế thừa các thuộc tính và phương thức từ một lớp cha (parent class), giúp lập trình viên viết mã linh hoạt, gọn gàng và dễ bảo trì hơn. Ngoài ra, JavaScript cũng cung cấp từ khóa super()
để gọi constructor hoặc phương thức của lớp cha trong lớp con, giúp việc kế thừa trở nên mạnh mẽ hơn.
Bài viết này sẽ đi sâu vào cách hoạt động của kế thừa trong JavaScript, từ cú pháp cơ bản đến các kỹ thuật nâng cao như method overriding, multilevel inheritance, và kế thừa phương thức tĩnh.
Kế thừa trong JavaScript là gì?
Kế thừa (Inheritance) là một trong những tính chất quan trọng của lập trình hướng đối tượng (OOP - Object-Oriented Programming). Nó cho phép một lớp con (subclass) kế thừa các thuộc tính và phương thức từ một lớp cha (parent class), giúp tái sử dụng mã nguồn và mở rộng chức năng của lớp cha mà không cần viết lại từ đầu.
Ví dụ: Nếu bạn có một lớp Animal
chứa các phương thức chung như eat()
hoặc sleep()
, bạn có thể tạo một lớp Dog
kế thừa từ Animal
để có thể sử dụng các phương thức này mà không cần định nghĩa lại chúng.
Lợi ích của kế thừa trong JavaScript
Kế thừa mang lại nhiều lợi ích trong lập trình, bao gồm:
-
Tái sử dụng mã nguồn: Lớp con có thể sử dụng lại các phương thức và thuộc tính của lớp cha, giúp giảm thiểu việc lặp lại mã.
-
Dễ bảo trì và mở rộng: Nếu có thay đổi trong lớp cha, tất cả các lớp con kế thừa nó cũng sẽ nhận được cập nhật mà không cần chỉnh sửa từng lớp riêng lẻ.
-
Cấu trúc rõ ràng, dễ hiểu: Việc kế thừa giúp tổ chức mã nguồn có hệ thống hơn, dễ đọc và dễ quản lý.
-
Hỗ trợ tính đa hình (Polymorphism): Lớp con có thể ghi đè (override) phương thức của lớp cha để thay đổi hành vi theo nhu cầu.
Sự khác biệt giữa kế thừa bằng prototype (trước ES6) và kế thừa bằng class (ES6+)
Trước ES6, JavaScript dựa vào prototype-based inheritance để thực hiện kế thừa, sử dụng Object.create()
hoặc thiết lập prototype thủ công. Tuy nhiên, từ ES6 trở đi, JavaScript cung cấp cú pháp class
và extends
, giúp kế thừa dễ hiểu và trực quan hơn.
Cách kế thừa | Trước ES6 (Prototype-based) | Từ ES6+ (Class-based) |
---|---|---|
Cách khai báo | Dùng Object.create() hoặc thiết lập prototype thủ công |
Dùng từ khóa class và extends |
Cách gọi constructor | Không có cú pháp super() , phải gọi thủ công |
Dùng super() để gọi constructor của lớp cha |
Dễ đọc & bảo trì | Khó hiểu, cú pháp phức tạp hơn | Dễ đọc, gần giống các ngôn ngữ OOP truyền thống |
Hỗ trợ OOP tốt hơn | Ít hỗ trợ, chủ yếu là mô phỏng | Hỗ trợ mạnh mẽ hơn với class, extends, super |
Ví dụ minh họa
Trước ES6 (Prototype-based Inheritance)
function Animal(name) { this.name = name; } Animal.prototype.eat = function() { console.log(`${this.name} is eating.`); }; function Dog(name, breed) { Animal.call(this, name); // Kế thừa thuộc tính từ Animal this.breed = breed; } Dog.prototype = Object.create(Animal.prototype); // Kế thừa phương thức từ Animal Dog.prototype.constructor = Dog; Dog.prototype.bark = function() { console.log(`${this.name} is barking.`); }; const myDog = new Dog("Buddy", "Golden Retriever"); myDog.eat(); // Output: Buddy is eating. myDog.bark(); // Output: Buddy is barking.
Từ ES6 (Class-based Inheritance)
class Animal { constructor(name) { this.name = name; } eat() { console.log(`${this.name} is eating.`); } } class Dog extends Animal { constructor(name, breed) { super(name); // Gọi constructor của lớp cha this.breed = breed; } bark() { console.log(`${this.name} is barking.`); } } const myDog = new Dog("Buddy", "Golden Retriever"); myDog.eat(); // Output: Buddy is eating. myDog.bark(); // Output: Buddy is barking.