Cảm ơn bạn!
JavaScript Class Inheritance và từ khóa super() có chức năng gì?
Chào các bạn, ở bài viết trước chúng ta đã tìm hiểu về class trong JavaScript, hôm nay chúng ta sẽ tìm hiểu về kế thừa trong JavaScript nhé!
Class Inheritance
Kế thừa các bạn có thể hiểu là nó cho phép chúng ta tạo một class, và class này có tất cả các chức năng từ một class cha (class mới thừa kế những chức năng từ class cha). Ngoài ra, kế thừa còn cho phép chúng ta thêm các chức năng mới.
👉 Các bạn có thể đọc về Prototype trong JavaScript để hiểu hơn về kế thừa trong JavaScript nhé.
Khi chúng ta sử dụng class inheritance, một class có thể kế thừa tất cả các methods và properties của một class khác.
Kế thừa là một tính năng rất hay cho phép chúng ta tái sử dụng các đoạn code.
Để sử dụng kế thừa của class, bạn sử dụng từ khóa extends
.
Ví dụ:
// parent class
class Person {
constructor(name) {
this.name = name;
this.blogName = 'homiedev.com'
}
greet() {
console.log(`Hello I'm ${this.name}`);
}
}
// class Student kế thừa các method, property từ Person
class Student extends Person {
}
let student1 = new Student('Trang');
student1.greet();
Ở ví dụ trên, class Student
kế thừa tất cả các methods và properties của class Person
. Do đó, Student
bây giờ sẽ có thuộc tính name
và method greet()
.
Kết quả chúng ta được:
Hello I'm Trang
Từ khóa super trong JavaScript và một số cách sử dụng
Từ khóa super
trong JavaScript được sử dụng để truy cập các properties của một object literal (sử dụng ký hiệu { }
) hoặc [[Prototype]] của class. Nó còn dùng để invoke (thực thi) hàm constructor
của parent class (lớp cha).
Syntax:
super([arguments]) // thực thi parent constructor
super.propertyOnParent
super[expression]
Chúng ta cùng xem qua một vài ví dụ về cách sử dụng từ khóa super
.
class Animal {
constructor(name) {
this.name = name;
console.log("Animal's constructor");
}
sleep() {
console.log(`${this.name} is sleeping 💤.`);
}
}
class Dog extends Animal {
constructor(name) {
super(name); // thực thi parent constructor - Animal constructor và truyền giá trị cho name
this.eat = '🍗';
}
}
const d = new Dog("BLAZE");
d.sleep(); // BLAZE is sleeping 💤.
Ở ví dụ trên, vì mình muốn tự tạo một constructor
cho class Dog
và muốn thêm thuộc tính eat vào constructor
này. Để thêm, sửa thuộc tính thì chúng ta sẽ sử dụng từ khóa this
như trên.
Khi sử dụng từ khóa super
như trên, nó sẽ thực thi hàm constructor
của Animal
như mình đã nói, cùng xem hình bên dưới nhé:
Vấn đề là tại sao chúng ta cần sử dụng từ khóa super
trong constructor
của class Dog
? để hiểu thì bây giờ mình thử xóa dòng super(name)
đi thử nhé. Kết quả chúng ta sẽ nhận được là:
class Dog extends Animal {
constructor(name) {
// super(name);
this.eat = "🍗";
}
}
const d = new Dog("BLAZE");
// ❌ Lỗi: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
d.sleep(); // BLAZE is sleeping 💤.
Lỗi trên xảy ra khi chúng ta sử dụng this
trước khi gọi super()
trong lớp con - Dog class.
Nguyên nhân là vì khi chúng ta tạo một constructor
trong lớp con (derived class), từ khóa this
trong hàm constructor
vẫn chưa được xác định hay chưa được khởi tạo. Vì vậy chúng ta cần xác định this
trong constructor
này là cái gì 😃, để làm được như vậy thì các bạn phải sử dụng từ khóa super
, nó sẽ thực thi hàm constructor của parent class (Animal) và từ đó this
trong constructor của Dog
class sẽ có các thuộc tính của lớp cha. Sau đó, các bạn có thể truy cập và chỉnh sửa các thuộc tính của this
.
Nếu chúng ta không định nghĩa một constructor
cho class thì JavaScript sẽ tự tạo một default constructor:
- Nếu class là parent class (base class), default constructor sẽ trống.
constructor() {}
- Nếu class là derived class, default constructor sẽ gọi parent constructor:
constructor(...args) {
super(...args);
}
👉 Đọc thêm: Spread Operator Javascript là gì?.
Khi parent class có method hoặc static field, chúng ta có thể truy cập chúng theo cách sau:
class Base {
static baseStaticField = 'homiedev.com';
baseMethod() {
return '🎉';
}
author = 'Nguyen Anh Vu';
}
class Extended extends Base {
extendedField = super.baseMethod(); // 🎉
static extendedStaticField = super.baseStaticField; // 'homiedev.com'
name = super.author; // undefined
}
Chúng ta có thể truy cập các static field và method như trên, vì từ khóa super
trong trường hợp này sẽ tìm các thuộc tính đó trong Base.prototype
. Còn với field name
sẽ nhận giá trị undefined, vì author
là một thuộc tính của Base
instance (một instance được tạo ra khi sử dụng từ khóa new
), nên chúng ta không thể sử dụng super
để truy xuất nó.
Cú pháp
super.prop
vàsuper[expr]
dùng được trong trường hợp chúng ta đang khởi tạo field, cònsuper(...arg)
hợp lệ khi được dùng trong hàm constructor của class.
Trong ví dụ này, super
được sử dụng với object literals:
const objA = {
methodA() {
console.log('method A');
}
}
const objB = {
methodB() {
super.methodA();
}
}
Object.setPrototypeOf(objB, objA);
objB.methodB(); // "method A"
Trong ví dụ trên, chúng ta định nghĩa hai method ở hai object khác nhau, trong methodB
ta sử dụng từ khóa super
để gọi methodA
, cách này hoạt động vì super
sẽ tìm methodA
ở prototype của objB
, mà prototype của objB
là objA
đã set thông qua method Object.setPrototypeOf()
.
Trên đây là bài viết về kế thừa trong JavaScript sử dụng class, chúng ta cũng đã tìm hiểu một số cách sử dụng của từ khóa super
. Hi vọng bài viết giúp ích cho các bạn. Cảm ơn các bạn đã đọc bài viết.
Nếu chưa rõ về nội dung ở trên, chúng ta cùng thảo luận ở phần bình luận nhé 😃.