Cú Pháp Class Trong JavaScript Cơ Bản
Có thể bạn quan tâm
Khi lập trình, chúng ta thường sẽ phải tạo ra nhiều object với cùng kiểu, ví dụ như: các đối tượng người dùng hay các đối tượng sản phẩm,...
Để giải quyết vấn đề này, bạn có thể sử dụng hàm khởi tạo với từ khóa new.
Tuy nhiên, từ ES6 trở đi, JavaScript có thêm từ khóa class, với nhiều đặc điểm và tính năng hữu ích được áp dụng trong lập trình hướng đối tượng.
Cú pháp cơ bản của class trong JavaScript
Cú pháp class cơ bản là:
class MyClass { // các phương thức của class constructor() { ... } method1() { ... } method2() { ... } method3() { ... } ... }Bạn sử dụng new MyClass() để tạo mới một đối tượng chứa tất cả các phương thức được định nghĩa trên.
Phương thức constructor() được gọi một cách tự động với từ khóa new. Do đó, bạn có thể khởi tạo các thuộc tính cho object trong hàm khởi tạo.
Ví dụ class User như sau:
class User { // hàm khởi tạo constructor(name) { // khởi tạo thuộc tính `this.name` với giá trị bằng `name` this.name = name; } // phương thức sayHi() { console.log(this.name); } } // Sử dụng: let user = new User("Alex"); user.sayHi(); // AlexKhi new User("Alex") được gọi:
- Một đối tượng mới được tạo ra.
- Hàm khởi tạo constructor được gọi với giá trị tham số truyền vào là "Alex" - gán cho this.name.
Sau đó, bạn có thể gọi phương thức của object, ví dụ: user.sayHi().
📝 Chú ý: Không tồn tại dấu phẩy giữa các phương thức. Việc thêm vào dấu phẩy vào giữa các phương thức sẽ gây lỗi cú pháp.
Bạn cần chú ý để tránh nhầm lẫn giữa việc định nghĩa class với việc định nghĩa object.
Class là gì?
Trong JavaScript, class thực chất là một loại Function. Và bạn có thể xem ví dụ sau để thấy rõ điều đó:
class User { constructor(name) { this.name = name; } sayHi() { console.log(this.name); } } // sử dụng typeof để xác định kiểu của User console.log(typeof User); // functionBản chất của class User {...} như sau:
- Tạo mới một hàm với tên là User, nội dung của hàm được lấy từ hàm khởi tạo constructor (mặc định là empty nếu bạn không định nghĩa).
- Lưu các phương thức của hàm (ví dụ sayHi) trong User.prototype.
Sau khi đối tượng mới được tạo ra và gọi một phương thức, JavaScript sẽ tự động tìm kiếm phương thức đó trong prototype (như đã miêu tả trong bài F.prototype).
Ví dụ chứng minh:
class User { constructor(name) { this.name = name; } sayHi() { console.log(this.name); } } // class là function console.log(typeof User); // function // User.prototype.constructor chính là User console.log(User === User.prototype.constructor); // true // Các phương thức được lưu trong User.prototype console.log(User.prototype.sayHi); // code của phương thức sayHi // Có tất cả 2 phương thức trong prototype console.log(Object.getOwnPropertyNames(User.prototype)); // constructor, sayHiClass không chỉ là "syntactic sugar"
Khái niệm syntactic sugar dùng để chỉ một cú pháp mới được sinh ra nhằm mục đích dễ đọc, dễ viết, chứ không tạo thêm những đặc điểm, tính chất mới so với cú pháp cũ.
Mọi người thường coi class là syntatic sugar của function. Vì thực chất là ta có thể định nghĩa được thứ tương tự class mà không cần từ khóa class như sau:
// *** Viết lại `class User` sử dụng hàm *** // 1. viết hàm khởi tạo function User(name) { this.name = name; } // prototype của hàm luôn có thuộc tính constructor mặc định, // nên không cần định nghĩa lại // 2. thêm thuộc tính vào prototype User.prototype.sayHi = function () { console.log(this.name); }; // Sử dụng: let user = new User("Alex"); user.sayHi(); // AlexBạn có thể thấy cách định nghĩa hàm trên cho kết quả khá giống với cách dùng class. Tuy nhiên, vẫn có một số đặc điểm khác giữa class và hàm như sau:
► Một hàm được tạo bởi từ khóa class luôn có một thuộc tính mặc định là [[IsClassConstructor]]: true. Và JavaScript engine thường dùng thuộc tính này để phân biệt giữa hàm bình thường và class.
Ví dụ class bắt buộc phải gọi với từ khóa new trong khi hàm bình thường thì không:
// hàm bình thường function User1() {} // class class User2 { constructor() {} } User1(); // không lỗi User2(); // lỗi: Class constructor User2 cannot be invoked without 'new'String biểu diễn class cũng luôn bắt đầu bằng class:
// hàm bình thường function User1() {} // class class User2 { constructor() {} } console.log(User1); // ƒ User1() {} console.log(User2); // class User2 { constructor() {} }► Các phương thức của class là non-enumerable - tức là không xuất hiện trong for...in. Bởi vì class luôn gán giá trị enumerable : false cho tất cả các phương thức trong prototype.
► Code trong class luôn sử dụng ở strict mode.
Ngoài ra, class còn có nhiều cú pháp và tính năng hay ho khác nữa sẽ được trình bày ở các bài viết sau.
Class expression
Giống như function, class cũng có class expression - biểu thức class. Nghĩa là nó có thể được định nghĩa bên trong một biểu thức khác, truyền giữa các hàm, làm giá trị trả về của hàm hoặc dùng để gán cho biến,...
Sau đây là ví dụ về class expression:
let User = class { sayHi() { console.log("Hello"); } };Tương tự như Named Function Expression - NFE, class expression cũng có thể có tên. Và nếu một class expression có tên thì tên đó chỉ được nhìn thấy bên trong class, ví dụ:
let User = class MyClass { sayHi() { // MyClass is chỉ được nhìn thấy bên trong class console.log(MyClass); } }; new User().sayHi(); // hiển thị định nghĩa MyClass // MyClass không được nhìn thấy bên ngoài console.log(MyClass); // ReferenceError: MyClass is not definedHoặc bạn có thể tạo động class như sau:
function makeClass(message) { // khai báo class và trả về nó return class { sayHi() { console.log(message); } };} // Tạo mới một class let User = makeClass("Hello"); // Tạo mới một đối tượng từ class new User().sayHi(); // HelloGetter/setter trong class
Class cũng có getter/setter như trong object. Ví dụ sau sử dụng user.name làm getter/setter:
class User { constructor(name) { this.name = name; // gọi hàm setter } // getter get name() { return this._name; } // setter set name(value) { if (value.length < 4) { alert("Name is too short."); return; } this._name = value; } } // Sử dụng: let user = new User("Alex"); console.log(user.name); // Alex user = new User(""); // Name is too short.Về cơ bản, cách định nghĩa getter/setter trong class như trên cũng giống như định nghĩa getter/setter trong User.prototype.
Tạo tên phương thức qua biểu thức
Tên của phương thức trong class có thể được tạo động thông qua một biểu thức, ví dụ:
class User { ["say" + "Hi"]() { console.log("Hello"); }} new User().sayHi(); // HelloTính năng này tương tự như trong object.
Thuộc tính trong class
Trong các phần trên, mình mới đề cập đến phương thức trong class. Thực tế, bạn có thể thêm bất cứ thuộc tính nào vào class như sau:
class User { // thêm thuộc tính name vào class name = "Alex"; sayHi() { console.log(`Hello, ${this.name}!`); } } new User().sayHi(); // Hello, Alex!Chú ý: nhiều trình duyệt cũ không hỗ trợ cách định nghĩa thuộc tính trong class như trên.
Điểm khác nhau quan trọng giữa việc định nghĩa phương thức và thuộc tính trong class là:
- Phương thức trong class được định nghĩa bên trong prototype.
- Thuộc tính trong class tồn tại ở mỗi object được tạo ra từ class.
Ví dụ:
class User { name = "Alex"; } let user = new User(); console.log(user.name); // Alexconsole.log(User.prototype.name); // undefinedBạn có thể gán giá trị cho thuộc tính thông qua một biểu thức hoặc qua gọi hàm như sau:
class User { name = prompt("Name, please?", "Alex");} let user = new User(); alert(user.name); // AlexTạo phương thức bind với thuộc tính trong class
Như mình đã đề cập trong bài viết về function binding, hàm trong JavaScript xử lý this một cách rất động.
Vì vậy, khi một object được truyền qua lại các hàm và được gọi ở một ngữ cảnh khác thì this có thể được tham chiếu đến object khác với object ban đầu.
Ví dụ đoạn code sau sẽ hiển thị undefined:
class Button { constructor(value) { this.value = value; } click() { console.log(this.value); } } let button = new Button("hello"); setTimeout(button.click, 1000); // undefinedVấn đề ở đây là khi phương thức button.click được truyền vào hàm setTimeout, phương thức này sẽ được gọi bởi một đối tượng khác, không phải button.
Có ba cách để giải quyết vấn đề này là:
► Cách 1: Sử dụng arrow function ở hàm setTimeout như sau:
setTimeout(() => button.click(), 1000);Khi đó, đối tượng gọi hàm click vẫn là button. Vì vậy, kết quả hiển thị vẫn chính xác.
► Cách 2: Sử dụng arrow function khi định nghĩa hàm click:
class Button { constructor(value) { this.value = value; } click = () => { console.log(this.value); };} let button = new Button("hello"); setTimeout(button.click, 1000); // helloVì arrow function không có this nên khi hàm click được gọi, this sẽ được lấy ở ngữ cảnh bên ngoài hàm - đó chính là đối tượng button.
► Cách 3: bind phương thức click cho đối tượng trong hàm khởi tạo.
class Button { constructor(value) { this.value = value; this.click = this.click.bind(this); } click() { console.log(this.value); } } let button = new Button("hello"); setTimeout(button.click, 1000); // undefinedVới cách này, giá trị của this bên trong phương thức click luôn là đối tượng button.
Tổng kết
Cú pháp cơ bản của class trong JavaScript như sau:
class MyClass { prop = value; // thuộc tính constructor(...) { // hàm khởi tạo // ... } method(...) {} // phương thức get something(...) {} // phương thức getter set something(...) {} // phương thức setter [Symbol.iterator]() {} // phương thức với tên được tính toán qua biểu thức // ... }MyClass thực chất là một hàm với nội dung của hàm lấy từ constructor và các phương thức, getter/setter được viết trong MyClass.prototype.
Trong các bài viết sau, mình sẽ tìm hiểu nhiều hơn về class, bao gồm tính kế thừa và các tính chất khác của lập trình hướng đối tượng.
Tham khảo: Class basic syntax
Từ khóa » Cách Tạo Class Trong Javascript
-
Class Trong JavaScript - NIIT - ICT Hà Nội
-
Hướng Dẫn Tạo Class Trong Javascript - Kipalog
-
Tìm Hiểu Class Trong Javascript - Viblo
-
Ba Cách Tạo Class Trong Javascript - Freetuts
-
Cách Tạo Class Trong Javascript (Hướng đối Tượng OOP ES6)
-
Class Trong JavaScript | Học Lập Trình JavaScript
-
Lớp Trong Javascript
-
Tìm Hiểu Class Trong Javascript - Niềm Vui Lập Trình
-
Cách Sử Dụng Javascript Class - VNTALKING
-
Class Trong JavaScript - Lập Trình Từ Đầu
-
Xu Hướng 7/2022 # Hướng Dẫn Tạo Class Trong Javascript # Top ...
-
Class Trong JavaScript
-
Thuộc Tính Và Phương Thức Static Của Class Trong Javascript
-
Sử Dụng Class Trong ES6 | Lê Vũ Nguyên Dạy Học Lập Trình