JavaScript vốn không phải là một ngôn ngữ nhẹ nhàng hoàn toàn theo hướng đối tượng hay hướng cấu trúc, mà nó lại thuộc dạng “nửa kia mỡ”. Đối với lập trình hướng cấu trúc trong JavaScript thì tạm thời mình không nói tới, nhưng lập trình hướng đối tượng trong JavaScript thì đúng là “chán”. By mang tiếng là có hỗ trợ hướng đối tượng, nhưng nó lại không hỗ trợ hết các tính chất của OOP, làm cho nhà phát triển cảm thấy bối rối khi code OOP với JavaScript
Qua bài viết này, chúng ta sẽ cùng nhau đi tìm hiểu về cách thiết lập hướng đối tượng trong JavaScript. Để xem nó hỗ trợ và không hỗ trợ những tính chất nào của OOP, nếu không hỗ trợ thì chúng ta có cách nào để thay thế không nhé
>> Đọc thêm. Lập trình hướng đối tượng – Hiểu cái ý đồ
lục mục
- 1. Khởi tạo class trong JavaScript
- 2. Thuộc tính của đối tượng trong JavaScript
- 3. Kế thừa lớp trong JavaScript
- 3. 1 Kế thừa hoàn toàn lớp cha
- 3. 2 Kế thừa và ghi đè phương thức khởi dựng ở lớp cha
- 3. 3 Kế thừa và ghi đè phương thức thông thường của lớp cha
- 4. Sử dụng lớp trừu tượng trong JavaScript
- 5. Sử dụng Giao diện trong JavaScript
- 6. Tổng kết
1. Khởi tạo class trong JavaScript
Từ phiên bản javascript es6 hay còn được biết đến với cái tên là es2015, JavaScript đã bổ sung thêm khái niệm lớp, giúp nhà phát triển dễ dàng triển khai mã hướng đối tượng hơn. Về cơ bản, một lớp trong JavaScript được khai báo và sử dụng như sau
class Person { say [] { return "Hello world"; } } var me = new Person[]; console.log[me.say[]]; // Hello world
Trông có vẻ ổn đấy chứ, các đối tượng trong JavaScript được khởi tạo thông qua từ khóa
class Person { constructor [name] { this.name = name } say [] { return "My name is " + this.name; } } var me = new Person["Bình"]; me.say []; // My name is Bình1 giống như bao ngôn ngữ lập trình hướng các đối tượng khác. Do đó, việc khai báo lớp và khởi tạo đối tượng trong JavaScript không có gì lạ cả. Tới đây mọi thứ vẫn thuộc về
2. Thuộc tính của đối tượng trong JavaScript
Chúng ta cùng xem xét ví dụ với một lớp
class Person { constructor [name] { this.name = name } say [] { return "My name is " + this.name; } } var me = new Person["Bình"]; me.say []; // My name is Bình0 có kèm theo thuộc tính
class Person { constructor [name] { this.name = name } say [] { return "My name is " + this.name; } } var me = new Person["Bình"]; me.say []; // My name is Bình1 xem thế nào nhé
class Person { constructor [name] { this.name = name } say [] { return "My name is " + this.name; } } var me = new Person["Bình"]; me.say []; // My name is Bình
Trông mọi thứ vẫn ổn. JavaScript cũng hỗ trợ hàm
class Person { constructor [name] { this.name = name } say [] { return "My name is " + this.name; } } var me = new Person["Bình"]; me.say []; // My name is Bình2 như các ngôn ngữ lập trình hướng đối tượng khác. Ấy à mà khoan, cứ để ý vào thân hàm
class Person { constructor [name] { this.name = name } say [] { return "My name is " + this.name; } } var me = new Person["Bình"]; me.say []; // My name is Bình2 xem
What what here?
this.name = name;
Đoạn mã trên là chúng ta đang gán tên giá trị cho thuộc tính với tên giá trị được truyền vào thông qua hàm tạo hàm. Vì vậy, câu hỏi đặt ra ở đây là thuộc tính tên này là công khai, riêng tư hay được bảo vệ?
Câu trả lời công khai. Bởi vì JavaScript không hỗ trợ đầy đủ tính năng đóng gói trong OOP, mọi thuộc tính của đối tượng đều có thể truy xuất được từ bên ngoài nếu biết chính xác tên thuộc tính là gì, điều này giống với công khai trong các ngôn ngữ lập trình
Mọi thứ bắt đầu xuất hiện rắc rối rồi, vậy có cách nào để khai báo thuộc tính cho javascript là riêng tư hay được bảo vệ không? . Tuy nhiên, bạn vẫn có thể mô phỏng các thuộc tính ở dạng riêng tư, được bảo vệ nhưng sẽ phức tạp – khuyến cáo bạn không nên cố gắng
3. Kế thừa lớp trong JavaScript
Trong Javascript, một lớp có thể kế thừa một lớp khác thông qua từ khóa
class Person { constructor [name] { this.name = name } say [] { return "My name is " + this.name; } } var me = new Person["Bình"]; me.say []; // My name is Bình4
Đối với kế thừa, chúng ta sẽ lần lượt xét 3 trường hợp
- class con only next class cha
- class con kế thừa và ghi đè phương thức khởi tạo ở class cha
- class con kế thừa và ghi đè các phương thức thông thường ở class cha
3. 1 Kế thừa hoàn toàn lớp cha
Các ví dụ được lấy sau, lớp
class Person { constructor [name] { this.name = name } say [] { return "My name is " + this.name; } } var me = new Person["Bình"]; me.say []; // My name is Bình5 chỉ đơn giản là mở rộng từ lớp
class Person { constructor [name] { this.name = name } say [] { return "My name is " + this.name; } } var me = new Person["Bình"]; me.say []; // My name is Bình0
class Person { constructor [name] { this.name = name } say [] { return "My name is " + this.name; } } var me = new Person["Bình"]; me.say []; // My name is Bình0
Việc kế hoạch một lớp con chỉ kế thừa lớp cha mà không ghi đè bất kỳ phương thức nào có vẻ ổn định, không có gì đáng bàn luận
3. 2 Kế thừa và ghi đè phương thức khởi dựng ở lớp cha
Vẫn là ví dụ tương tự như trên, nhưng giờ ở lớp
class Person { constructor [name] { this.name = name } say [] { return "My name is " + this.name; } } var me = new Person["Bình"]; me.say []; // My name is Bình5 mình sẽ ghi đè phương thức khởi tạo ở lớp
class Person { constructor [name] { this.name = name } say [] { return "My name is " + this.name; } } var me = new Person["Bình"]; me.say []; // My name is Bình0 xem thế nào nhé
class Person { constructor [name] { this.name = name } say [] { return "My name is " + this.name; } } var me = new Person["Bình"]; me.say []; // My name is Bình3
Nhìn đoạn mã có vẻ ổn, nhưng thực chất bạn sẽ nhận ra lỗi thế này
lỗi. Lỗi loại chưa bắt được. Không thể đặt thuộc tính 'tên' của không xác định
Nguyên nhân là đối với JavaScript, nếu bạn muốn ghi đè phương thức khởi tạo của lớp cha thì ở lớp con phải gọi hàm
class Person { constructor [name] { this.name = name } say [] { return "My name is " + this.name; } } var me = new Person["Bình"]; me.say []; // My name is Bình9
class Person { constructor [name] { this.name = name } say [] { return "My name is " + this.name; } } var me = new Person["Bình"]; me.say []; // My name is Bình9 là hàm tham chiếu tới phương thức ở lớp cha
Ví dụ trên cần phải được thay đổi lại như sau
class Person { constructor [name] { this.name = name } say [] { return "My name is " + this.name; } } var me = new Person["Bình"]; me.say []; // My name is Bình6
Hải lưu ý quan trọng
– Thứ 1. Nếu trong lớp bạn không khai báo hàm tạo phương thức thì mặc định nó luôn có một hàm tạo lớp với thân hàm rỗng. Vì vậy, trong bất kỳ trường hợp nào, nếu muốn ghi đè phương thức khởi tạo ở lớp cha [cho dù lớp cha không được bạn khai báo hàm khởi tạo] thì bạn vẫn phải gọi hàm super[].
– Thứ 2. Hàm super[] phải được gọi trước khi bạn chuyển tới
this.name = name;1 trong thân hàm, nếu không sẽ bị lỗi tham chiếu tới lớp cha. Cách tốt nhất là gọi hàm super[] ngay dòng đầu tiên của thân hàm constructor[].
3. 3 Kế thừa và ghi đè phương thức thông thường của lớp cha
Vẫn là ví dụ tương tự, giờ ở lớp
class Person { constructor [name] { this.name = name } say [] { return "My name is " + this.name; } } var me = new Person["Bình"]; me.say []; // My name is Bình5 mình sẽ thử ghi ngược phương thức
this.name = name;3 xem thế nào
class Person { constructor [name] { this.name = name } say [] { return "My name is " + this.name; } } var me = new Person["Bình"]; me.say []; // My name is Bình0
Đoạn mã trên chạy ngon, với phương thức
this.name = name;3 đã trả về “
this.name = name;5” thay vì “
this.name = name;6” như lúc trước. Có nghĩa là việc ghi đè phương thức thông thường ở lớp cha chỉ đơn giản là tạo một phương thức khác ở lớp con có tên trùng với phương thức muốn ghi đè
Ấy khoan, thế nào nếu muốn ghi đè, nhưng vẫn thực hiện logic ở phương thức ở lớp cha thì làm thế nào?
Ví dụ
class Person { constructor [name] { this.name = name } say [] { return "My name is " + this.name; } } var me = new Person["Bình"]; me.say []; // My name is Bình7
Trải qua 3 trường hợp kế thừa trong JavaScript thì mình thấy nó cũng ổn, không có điều gì đặc biệt lắm
4. Sử dụng lớp trừu tượng trong JavaScript
Thật buồn, hiện tại [2019] thì JavaScript không hỗ trợ khái niệm lớp trừu tượng. Nhưng may mắn là chúng ta vẫn có thể dễ dàng mô phỏng một lớp trừu tượng dựa trên các tính chất của nó mà chúng ta vẫn thường hiểu là
- Lớp trừu tượng không thể sử dụng để khởi động
- Các lớp mở rộng lớp trừu tượng đều phải triển khai một số phương thức cụ thể và thuộc tính do lớp trừu tượng quy định
Các bạn có thể tham khảo lớp
class Person { constructor [name] { this.name = name } say [] { return "My name is " + this.name; } } var me = new Person["Bình"]; me.say []; // My name is Bình00 trong ví dụ dưới đây để biết cách mô phỏng một lớp trừu tượng trong JavaScript
class Person { constructor [name] { this.name = name } say [] { return "My name is " + this.name; } } var me = new Person["Bình"]; me.say []; // My name is Bình9
class Person { constructor [name] { this.name = name } say [] { return "My name is " + this.name; } } var me = new Person["Bình"]; me.say []; // My name is Bình01 sẽ trả về tên lớp được khởi tạo sau từ khóa
class Person { constructor [name] { this.name = name } say [] { return "My name is " + this.name; } } var me = new Person["Bình"]; me.say []; // My name is Bình1. Bạn có thể tham khảo thêm ở đây .
5. Sử dụng Giao diện trong JavaScript
Đến lớp trừu tượng mà JavaScript còn không hỗ trợ thì bạn nghĩ sao về giao diện. Cách tốt nhất là bạn nên quên khái niệm giao diện đi nếu bạn đang lập trình với JavaScript, đơn giản là nó không hỗ trợ giao diện và việc mô phỏng một giao diện [giống như mình mô phỏng lớp trừu tượng ở trên] quá phức tạp
6. Tổng kết
In set the direction object has 4 tính chất quan trọng là. tính đóng gói, tính hiển thị, tính đa hình, tính kế thừa. Thì với JavaScript, các tính chất trên được thể hiện ở mức độ như sau
- Tính đóng gói. Hỗ trợ kém
- Tính năng hiển thị đối tượng. Hỗ trợ kèm theo
- Tính đa hình. Tốt
- Kế thừa kế thừa. Tốt
Đánh giá tổng quan. 5/10 điểm. Với số lượng khoảng cách khoảng này, bạn vẫn có thể thiết lập hướng đối tượng trình với JavaScript được, tuy nhiên sẽ gặp khó khăn trong việc mô phỏng tính đóng gói và tính đối tượng
Có cách nào cải thiện khả năng hướng đối tượng của JavaScript không?
Câu trả lời là có, bạn có thể sử dụng ngôn ngữ JavaScript tiền tệ [các ngôn ngữ sẽ biên dịch ra mã JavaScript rồi mới chạy] như TypeScript không có giới hạn. TypeScript cung cấp cú pháp hướng đối tượng trong JavaScript sáng hơn, nhưng cuối cùng TypeScript sẽ được biên dịch thành mã JavaScript để chạy
JavaScript vốn sida vậy, theo bạn nó đang có để theo học hay không?
Bài viết được viết dựa trên kinh nghiệm cá nhân, rất mong nhận được sự góp ý của các bạn
Chúc các bạn học tập hiệu quả
Bài viết trước Những điều khiến nhà phát triển thường FA
Bài viết tiếp theo Tóm gọn JavaScript es6 trong 10 phút
Phạm Bình
https. //phuongbinh. mạng lưới
Mình muốn chia sẻ những kiến thức mà mình học được trong quá trình làm việc và phát triển, với hy vọng sẽ giúp ích cho bạn đọc - như cách mà mình học được từ việc đọc các blog khác