Chúng ta đã biết, mọi thứ trong JS đều là object và do đó mà JS là một ngôn ngữ Object Oriented Programming.
Để có thể dùng đi dùng lại một “blueprint” của nhóm các đối tượng thì ta cần sử dụng class, một tính năng xuất hiện trong JS ở phiên bản ES6.
Class Declaration
Tên của lớp đối tượng sử dụng CamelCase.
class Person {
name
// Default value
age = 20
// Private property
#isMarried = false
// Method
getName() {
return this.name
}
}Một sự khác biệt của function và class là tính Hoisting (đưa lên đầu). Trong khi hàm có thể gọi trước khi được định nghĩa thì lớp đối tượng cần phải định nghĩa trước khi được gọi.
const p = new Rectangle() // ReferenceError
class Rectangle {}Ngoài ra, có thể sử dụng cách khác, gọi là Class Expression để khai báo lớp đối tượng.
Class Instantiation
Để khởi tạo một đối tượng từ lớp đối tượng, ta sử dụng từ khóa new:
class Person {
name
// Default value
age = 20
// Private property
#isMarried = false
}
const person = new Person()
console.log(person) // Person {name: undefined, age: 20}Class Constructor
Ta có thể thiết lập một constructor để vừa thêm thuộc tính vừa khởi tạo giá trị của chúng.
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
}
const person = new Person("Quân", 20)
console.log(person) // Person {name: 'Quân', age: 20}Info
- Cũng có thể thiết lập default constructor cho lớp đối tượng.
- Tuy nhiên, một class chỉ có thể có một constructor duy nhất do JS không có overloading trong cùng một class.
Prototype
Để thêm một thuộc tính hoặc phương thức vào lớp đối tượng sau khi lớp đối tượng được tạo ra thì ta sử dụng từ khóa prototype.
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
}
Person.prototype.hair = "curly"
Person.prototype.getAge = function () {
return this.age
}
const person = new Person("Quân", 20)
console.log(person.hair) // "curly"
console.log(person.getAge()) // 20Important
Cần phân biệt với việc thêm thuộc tính hoặc phương thức vào đối tượng, khi đó chúng ta chỉ cần sử dụng toán tử
.
Class Methods
Phương thức của lớp đối tượng trong JS cũng có nguyên lý hoạt động tương tự C-C++:
class Person {
constructor(firstName, lastName, age) {
this.firstName = firstName
this.lastName = lastName
this.age = age
}
// Do not use `funtion` keyword or `=>` syntax
getFullName() {
const fullName = this.firstName + " " + this.lastName
return fullName
}
}
const person = new Person("Quân", "Lê Minh", 25)
console.log(person.getFullName()) // Quân Lê MinhTip
Muốn khai báo phương thức tĩnh (Static) thì đặt từ khóa
statictrước tên phương thức.
Summary
Tóm lại:
- Thêm vào đối tượng: toán tử
..- Thêm vào lớp đối tượng: từ khóa
prototype.- Gọi từ đối tượng: toán tử
.hoặc toán tử[]nếu là thuộc tính.- Gọi từ lớp đối tượng: có từ khóa
static, sử dụng tên lớp đối tượng.
OOP in JS
Inheritance
Để kế thừa từ một lớp cơ sở, sử dụng từ khóa extends, thay vì dùng access modifier (::) như C++.
class Student extends Person {
saySomething() {
console.log("I am a child of the person class")
}
}
// Using parent class's constructor
const person = new Student("Quân", "Lê Minh", 20)
console.log(person.firstName) // Quân
person.saySomething() // I am a child of the person classPolymorphism
Chúng ta có thể overriding các hàm của lớp cơ sở bên trong lớp dẫn xuất. Chẳng hạn, có thể tạo một constructor riêng cho lớp dẫn xuất thay vì gọi constructor của lớp cơ sở rồi thêm các thuộc tính và phương thức mà chúng ta cần.
Từ khóa super dùng để truy cập và gọi phương thức của lớp cơ sở bên trong phương thức của lớp dẫn xuất. Nếu super được sử dụng trong constructor của lớp dẫn xuất, nó cần phải đi một mình và đứng trước các câu lệnh sử dụng this.
class Student extends Person {
constructor(firstName, lastName, age, gender) {
super(firstName, lastName, age) // call parent constructor
this.gender = gender
}
}
const person = new Student("Quân", "Lê Minh", 20, 1)
console.log(person.age) // 20Đoạn code trên customize một constructor riêng cho lớp dẫn xuất. Nếu ở lớp dẫn xuất có một phương thức trùng tên với lớp cơ sở, tính đa hình (Polymorphism) sẽ nhập cuộc. Nói cách khác, phương thức ở lớp dẫn xuất sẽ ghi đè lên phương thức của lớp cơ sở.
Info
Khi gọi một hàm của lớp cơ sở, không nhất thiết phải truyền hết tất cả các tham số.
class Student extends Person {
constructor(firstName, lastName, age, gender) {
super(firstName, age) // call parent constructor without lastName property
this.lastName = ""
this.gender = gender
}
}