Cách tạo class trong javascript ?

Hôm nay mình sẽ giới thiệu với bạn về class trong JavaScript. Class được tạo ra như thế nào? Sử dụng class ra sao. Hãy theo dõi nhé!


1. Class là gì?

Class có thể hiểu là một khuôn mẫu.

Trong lập trình hướng đối tượng class [hay lớp] được sử dụng để tạo ra các đối tượng [mà mình đã giới thiệu ở bài đối tượng trong JavaScript].

Đối tượng thì sẽ có các thuộc tính, phương thức.

Các đối tượng giống nhau sẽ có những thuộc tính và phương thức giống nhau.

Từ phiên bản ECMAScript 6 thì JavaSript hỗ trợ tạo ra class giống các ngôn ngữ lập trình hướng đối tượng khác [Java, PHP, Python...].

Tham khảo:

  • KHÓA HỌC JAVA
  • KHÓA HỌC PHP
  • KHÓA HỌC PYTHON

Có thể xem như việc sử dụng class và object sẽ giúp chúng ta có cái nhìn chuẩn hơn về code và để những bạn mới tiếp cận lập trình JavaSript cũng thấy gần gũi hơn.

Cú pháp để tạo ra một class trong JavaSript:

// Hàm khởi tạo

constructor[] { ... }

// Các phương thức

phuongThuc1[] { ... }

phuongThuc2[] { ... }

phuongThuc3[] { ... }

}

}
 

Đây là ví dụ khi khai báo Object mà mình đã giới thiệu ở bài trước:

// Tạo các thuộc tính

hoTen: 'Ngô Minh Trung',

gioiTinh: 'Nam',

MSSV: 'B1704863',

namSinh: '1999',

// Tạo các phương thức

hocBai: function[] {

console.log['Đang học bài...'];

},

diNgu: function[] {

console.log['Đang ngủ...'];

},

xemPhim: function[] {

console.log['Đang xem phim...'];

}

}
 

Nhưng ở đây, ta chỉ tạo được một đối tượng cụ thể.

Nếu muốn tạo ra đối tượng khác thì ta lại phải viết code lại gần như từ đầu.

Nếu các đối tượng sinh viên tạo ra cũng có các thuộc tính giống nhau như: hoTen, gioiTinh, MSSV, namSinh...

Và các thuộc tính chung như hocBai, diNgu, xemPhim....

Thì có nghĩa là code của bạn chưa tối ưu.

Code thừa rất nhiều.

Để tránh vấn đề này, chúng ta có class:

// Tạo ra một class SinhVien

class SinhVien {

//Hàm khởi tạo 

constructor[hoTengioiTinhMSSVnamSinh] {

this.hoTen = hoTen;

this.gioiTinh = gioiTinh;

this.namSinh = namSinh;

this.MSSV = MSSV;

}

//Khai báo phương thức

hocBai[] {

console.log['Đang học bài...'];

}

diNgu[] {

console.log['Đang ngủ...'];

}

xemPhim[] {

console.log['Đang xem phim...'];

}

}
 

Đây có thể hiểu như là một khuôn mẫu chung cho các đối tượng sinh viên.

Khi muốn tạo ra đối tượng cụ thể thì ta sẽ sử dụng class SinhVien này.

// Tạo đối tượng từ class SinhVien

var sinhVien1 = new SinhVien[];

var sinhVien2 = new SinhVien[];

var sinhVien3 = new SinhVien[];
 

> Lưu ý: Theo quy tắc thì bạn nên đặt tên class là viết HOA chữ cái đầu tiên như SinhVien, GiangVien, NhanVien...

2. Constructor là gì?

Phương thức khởi tạo [constructor hay là hàm khởi tạo] là một phương thức đặc biệt để tạokhởi tạo một đối tượng từ một class nào đó.

Nó sẽ tự động được gọi khi bạn tạo ra một đối tượng từ class.

Chỉ có thể có một phương thức đặc biệt với tên là “constructor” trong một lớp.

Một lỗi syntaxError sẽ được quăng ra nếu lớp có nhiều hơn một lần xuất hiện của một phương thức khởi tạo.

Tức là JavaScript không hỗ trợ có nhiều constructor như các ngôn ngữ khác.

Một ví dụ về constructor:

constructor[hoTengioiTinhMSSVnamSinh] {

this.hoTen = hoTen;

this.gioiTinh = gioiTinh;

this.namSinh = namSinh;

this.MSSV = MSSV;

}
 

Như vậy để tạo hàm constructor thì chỉ cần dùng từ khóa constructor và truyền vào danh sách tham số là các thuộc tính của class.

Sau đó gán các thuộc tính của lớp bằng từ khóa this.

Bạn nhìn như thế này sẽ dễ hiểu hơn:

constructor[abcd] {

this.hoTen = a;

this.gioiTinh = b;

this.namSinh = c;

this.MSSV = d;

}
 

Sau đó khi khởi tạo đối tượng thì ta sẽ truyền đối số như thế này:

var sinhVien1 = new SinhVien[abcd];
 

Tuy nhiên, để sau này dễ dàng biết thuộc tính nào kết nối với tham số nào thì chúng ta nên sử dụng tên tham số và đối số trong hàm constructor giống nhau.

constructor[hoTengioiTinhMSSVnamSinh] {

this.hoTen = hoTen;

this.gioiTinh = gioiTinh;

this.namSinh = namSinh;

this.MSSV = MSSV;

}
 

> Ghi chú: Khi tạo class thì ta gọi là tham số. Khi khởi tạo và truyền dữ liệu thì ta gọi nó là đối số

Chúng ta có nhiều cách gọi hàm như trong bài hàm mình có đề cập đến.

Ví dụ như sau:

// Khởi tạo các đối tượng sinh viên

var sinhVien1 = new SinhVien["Ngô Minh Trung""Nam""B1704863""1999"];

var sinhVien2 = new SinhVien["Nguyễn Minh Đức""Nam"];

var sinhVien3 = new SinhVien[];

// Log ra thông tin đối tượng

console.log[sinhVien1];

console.log[sinhVien2];

console.log[sinhVien3];
 

Kết quả ta được như sau:


> Lưu ý: Kể cả khi bạn không định nghĩa rõ ràng một constructor. JavaScript cũng sẽ tự động thêm vào một constructor rỗng

3. Phương thức getter và setter trong JavaScript

Các phương thức getter và setter được sử dụng để truy cập / sửa đổi thuộc tính trong class.

Có thể hiểu là một loại hàm để lấy dữ liệu và một loại hàm dùng đế gán dữ liệu.

3.1. Phương thức getter

Các phương thức getter được sử dụng để truy cập các thuộc tính của một đối tượng.

Để tạo phương thức getter trong JavaScript, chúng ta sử dụng từ khóa get.

Ví dụ:

// Các phương thức getter

get getHoTen[] {

return this.hoTen;

}

get getGioiTinh[] {

return this.gioiTinh;

}

get getNamSinh[] {

return this.hoTen;

}

get getMSSV[] {

return this.MSSV;

}
 

Có bao nhiêu thuộc tính thì sẽ có bấy nhiêu hàm getter trong class.

Khi chúng ta sử dụng, chúng ta có thể truy cập giá trị như là một thuộc tính.

Ví dụ:

var sinhVien1 = new SinhVien["Ngô Minh Trung""Nam""B1704863""1999"];

// Truy cập giới tính thông qua phương thức getter

console.log[sinhVien1.getGioiTinh];
 

Ngay cả khi getter là một phương thức, nếu bạn cố gắng truy cập giá trị dưới dạng một phương thức [sử dụng ngoặc tròn [] ] như thế này:

console.log[sinhVien1.getGioiTinh[]];
 

Thì sẽ bị lỗi:

Uncaught TypeError: sinhVien1.getGioiTinh is not a function

3.2. Phương thức setter

Phương thức setter cho phép bạn thay đổi giá trị của thuộc tính của đối tượng.

Để tạo ra phương thức setter ta sử dụng từ khóa set

Ví dụ:

this.hoTen = hoTen;

}

set setGioiTinh[gioiTinh] {

this.gioiTinh = gioiTinh;

}

set setNamSinh[namSinh] {

this.namSinh = namSinh;

}

set setMSSV[MSSV] {

this.MSSV = MSSV;

}
 

Cũng tương tự getter, setter cũng vậy có bao nhiêu thuộc tính thì chúng ta tạo bấy nhiêu hàm setter.

Để sử dụng phương thức setter bạn phải truyền vào đối số tương ứng.

var sinhVien1 = new SinhVien["Ngô Minh Trung""Nam""B1704863""1999"];

// Thiết lập lại giới tính

sinhVien1.setGioiTinh = "Nữ";

// Log ra giới tính hiện tại

console.log[sinhVien1.getGioiTinh];
 

Hiện tại, giới tính đã đổi từ Nam thành Nữ

> Lưu ý #1: JavaScript không hỗ trợ đầy đủ tính đóng gói trong Lập trình hướng đối tượng như Java, PHP hay Python. Vì thế, mọi thuộc tính đều có thể truy cập nếu bạn biết tên của thuộc tính đó [Giống như phạm vi truy cập public trong Java, tham khảo trong hướng dẫn: HỌC LẬP TRÌNH JAVA].

> Lưu ý #2: JavaScript nguyên bản thì không hỗ trợ private, protected nhưng bạn có thể mô phỏng chúng [Tuy nhiên sẽ hơi rắc rối đó]

4. Phương thức tĩnh [Static method]

Từ khóa static định nghĩa một phương thức static cho một lớp, còn được gọi là phương thức tĩnh.

Các phương thức tĩnh được gọi mà không cần khởi tạo lớp của chúng và không thể được gọi thông qua một đối tượng của lớp.

Phương thức tĩnh thường được sử dụng để tạo các chức năng tiện ích cho một ứng dụng.

Ví dụ:

constructor[xy] {

this.x = x;

this.y = y;

}

static distance[ab] {

const dx = a.x - b.x;

const dy = a.y - b.y;

return Math.hypot[dxdy];

}

}

const p1 = new Point[55];

const p2 = new Point[1010];

p1.distance//undefined

p2.distance//undefined

console.log[Point.distance[p1p2]]; // 7.0710678118654755
 

Chúng ta không thể gọi hàm distance thông qua p1 hoặc p2. Mà phải gọi trực tiếp từ class của nó đó chính là Point.

5. Hoisting đối với class

Không giống như các hàm và các khai báo JavaScript khác, các khai báo class [lớp] không được hoisting.

var sinhVien1 = new SinhVien["Ngô Minh Trung"];

class SinhVien {

constructor[name] {

this.hoTen = hoTen;

}

}
 

Ví dụ trên sẽ tạo ra lỗi.

Để tránh lỗi, bạn phải khai báo một lớp trước khi bạn có thể sử dụng nó, như vậy:

constructor[name] {

this.hoTen = hoTen;

}

}

var sinhVien1 = new SinhVien["Ngô Minh Trung"];
 


6. Kế thừa class

JavaScript cũng hỗ trợ tính kế thừa [inheritance] như các ngôn ngữ khác, để tạo một lớp kế thừa, bạn sử dụng từ khóa extends.

class SinhVien extends ConNguoi {...}
 

Kế thừa cho chúng ta khả năng sử dụng lại code đã viết.

Sử dụng lại các thuộc tính và phương thức của một lớp có sẵn khi tạo một lớp mới giúp chúng ta tiết kiệm thời gian làm việc.

Một lớp được kế thừa từ lớp cha sẽ có tất cả tác phương thức từ lớp cha.

Ví dụ: Ta có một lớp ConNguoi và một lớp SinhVien được kế thừa từ lớp ConNguoi

constructor[hoTennamSinh] {

this.hoTen = hoTen || "unknown";

this.namSinh = namSinh || "unknown";

}

getHoTen[] {

return "Tên " + this.hoTen + ", sinh năm " + this.namSinh;

}

}

class SinhVien extends ConNguoi {

constructor[maSSVhoTennamSinh] {

super[hoTennamSinh];

this.maSSV = maSSV || "unknown";

}

getThongTin[] {

return this.getHoTen[] + ", mã sinh viên " + this.maSSV;

}

}

var sinhVien1 = new SinhVien["B1704863""Ngô Minh Trung""1999"];

console.log[sinhVien1.getThongTin[]];
 

Kết quả:

Tên Ngô Minh Trung, sinh năm 1999, mã sinh viên B1704863
 

Qua đoạn code trên ta thấy:

  • Xuất hiện từ khóa super: Phương thức super[] này là phương thức tham chiếu đến lớp cha. Khi chúng ta gọi phương thức super[] trong hàm khởi tạo thì chúng ta gọi đến phương thức khởi tạo của lớp cha và có quyền truy cập đến các thuộc tính và phương thức khởi tạo của lớp cha.

  • Chúng ta cũng có thể gọi phương thức của lớp cha thông qua từ khóa super[] khi chúng ta overwride phương thức đó.

Ví dụ:

constructor[hoTennamSinh] {

this.hoTen = hoTen || "unknown";

this.namSinh = namSinh || "unknown";

}

getThongTin[] {

return "tên " + this.hoTen + ", sinh năm " + this.namSinh;

}

}

class SinhVien extends ConNguoi {

constructor[maSSVhoTennamSinh] {

super[hoTennamSinh];

this.maSSV = maSSV || "unknown";

}

// Ghi đè phương thức

getThongTin[] {

return [

"MSSV " + this.maSSV + ", " + super.getThongTin[]

];

}

}

var sinhVien1 = new SinhVien["B1704863""Ngô Minh Trung""1999"];

console.log[sinhVien1.getThongTin[]];
 

Kết quả được như sau:

MSSV B1704863, tên Ngô Minh Trung, sinh năm 1999
 

Như vậy, ở class SinhVien mình đã ghi đè thành công phương thức getThongTin[]

7. Từ khóa this trong class

Về từ khóa this thì thường bạn sẽ gặp trong các ngôn ngữ lập trình hướng đối tượng khác, nó là một thể hiện cho đối tượng đang chứa đoạn code đang được thực thi.

this thường được chỉ đến Object chứa phương thức đang được gọi thực thi.

Từ khóa this được mình sử dụng ở các phần trước.

constructor[hoTennamSinh] {

this.hoTen = hoTen || "unknown";

this.namSinh = namSinh || "unknown";

}

getThongTin[] {

return "Tên " + this.hoTen + ", sinh năm " + this.namSinh;

}

}
 

Với class này mình sử dụng từ khóa this. 

Khi đoạn code được biên dịch thì hàm constructor[] được gọi, thì sử dụng con trỏ this.hoTen và this.namSinh trong hàm contructor[] được hiểu là class ConNguoi.

8. Kiểm tra loại đối tượng với instanceof

instanceof còn có tác dụng xác định xem đối tượng có phải là một thể hiện [đối tượng] của một class hay không.

Để mình ví dụ:

constructor[hoTennamSinh] {

this.hoTen = hoTen || "unknown";

this.namSinh = namSinh || "unknown";

}

getThongTin[] {

return "Tên " + this.hoTen + ", sinh năm " + this.namSinh;

}

}

var sinhVien1 = new ConNguoi["Ngô Minh Trung""1999"];

var sinhVien2 = {};

console.log[sinhVien1 instanceof ConNguoi]; // true

console.log[sinhVien2 instanceof ConNguoi]; // False
 

Như vậy ta sẽ thấy sinhVien1 là một thể hiện [đối tượng] của lớp ConNguoi, thế nên câu lệnh này trả về giá trị true.

Còn đối với sinhVien2 là đối tượng trống, thì không phải là thể hiện của ConNguoi nên nó sẽ là false.

instanceof còn có thể xác định là một thể hiện của lớp con có phải là một thể hiện của lớp cha.

Ví dụ:

constructor[hoTennamSinh] {

this.hoTen = hoTen || "unknown";

this.namSinh = namSinh || "unknown";

}

getHoTen[] {

return "Tên " + this.hoTen + ", sinh năm " + this.namSinh;

}

}

class SinhVien extends ConNguoi {

constructor[maSSVhoTennamSinh] {

super[hoTennamSinh];

this.maSSV = maSSV || "unknown";

}

getThongTin[] {

return this.getHoTen[] + ", mã sinh viên " + this.maSSV;

}

}

var sinhVien1 = new SinhVien["B1704863""Ngô Minh Trung""1999"];

console.log[sinhVien1 instanceof SinhVien]; // true

console.log[sinhVien1 instanceof ConNguoi]; // true
 

Kết quả cả hai đều trả về true có nghĩa là sinhVien1 vừa là thể hiện của SinhVien và cũng là thể hiện của ConNguoi [lớp cha của SinhVien].

9. Class và prototypes

Cú pháp lớp [class] trong JavaScript thực hiện trừu tượng hóa các nguyên mẫu [prototypes] một cách tuyệt vời.

Các lớp được xây dựng từ việc kế thừa các nguyên mẫu. Mọi lớp đều được xem như là một hàm và tạo ra một thể hiện khi được gọi như một hàm tạo.

Chúng ta hãy so sánh hai đoạn mã sau nhé.

Đoạn code 1 sử dụng từ khóa class:

constructor[hoTennamSinh] {

this.hoTen = hoTen || "unknown";

this.namSinh = namSinh || "unknown";

}

getThongTin[] {

return "Tên " + this.hoTen + ", sinh năm " + this.namSinh;

}

}

var sinhVien1 = new ConNguoi["Ngô Minh Trung"1999];

console.log[sinhVien1.getThongTin[]];

console.log[sinhVien1 instanceof ConNguoi];
 

Đoạn code thứ 2 sử dụng prototype [tương tự như tạo object ở bài trước]

function ConNguoi[hoTennamSinh] {

this.hoTen = hoTen || "unknown";

this.namSinh = namSinh || "unknown";

}

ConNguoi.prototype.getThongTin = function[] {

return "Tên " + this.hoTen + ", năm sinh" + this.namSinh;

}

var sinhVien1 = new ConNguoi["Ngô Minh Trung"1999];

console.log[sinhVien1.getThongTin[]];

console.log[sinhVien1 instanceof ConNguoi];
 

Đây là hai đoạn code tương đương với nhau. Đối với từ khóa class sẽ dễ sử dụng hơn nếu bạn đã quen với cách lập trình của ngôn ngữ Java hoặc C#.

Nếu bạn thích sử dụng từ khóa class hơn thì các bạn cũng nên hiểu rõ về kế thừa prototype nhé. Vì trong JavaScript prototype rất quan trọng.

Tổng kết

MÌnh vừa giới thiệu các bạn về class trong JavaSript đây chính là một điểm mới tránh các rườm rà của Object trước đây, class tường minh hơn sẽ dễ tiếp cận hơn.

Ngoài ra, mình cũng đã giới thiệu các bạn về một số khái niệm khác liên quan đến class trong JavaScript. Đây chỉ mới là một chút nền tảng cho các bạn học những thư viện hay framework của JavaScript về sau.

Hẹn gặp lại bạn ở bài học tiếp theo.

Chủ Đề