Hướng đối tượng trong javaScript

14/01/2013 15:10
Trong javaScript đối tượng được tạo trực tiếp và có thể tạo bằng nhiều cách , đối tượng cũng có thể kế thừa từ đối tượng khác

Không giống như hầu hết các ngôn ngữ hướng đối tượng khác, trên thực tế javaScript không thực sự có khái niệm lớp, trong hầu hết các ngôn ngữ lập trình bạn phải xây dựng lớp sau đó mới khai báo đối tượng để sử dụng. Trong javaScript đối tượng được tạo trực tiếp và có thể tạo bằng nhiều cách , đối tượng cũng có thể kế thừa từ đối tượng khác. Để tạo đối tượng bạn có hai cách cơ bản để tạo đối tượng như sau:

01 // Tạo đối tượng thông qua cú pháp new Object()
02 var obj = new Object();
03 // Tạo một số thuộc tính cho đối tượng
04 obj.val = 5;
05 obj.click = function () {
06   alert("hello");
07 };
08
09 // Sử dụng cách viết ngắn gọn bằng cách dùng dấu {...}
10 var obj = {
11   val: 5,
12   click: function () {
13     alert("hello");
14   }
15 };

Trong thực tế khi bạn khai báo một hàm bất kỳ trong javaScript cũng có thể được mô tả cho một đối tượng, trong thực tế điều này có thể gây nhiều khó hiểu. Chúng ta sẽ cùng xem xét ví dụ sau để hiểu rõ hơn điều này:

01 // Tạo một hàm đơn giản, bên trong có tạo một thuộc tính name
02 function User(x) {
03   this.name = x;
04 }
05 // Khai báo đối tượng từ hàm trên
06 var me = new User("My Name");
07 // Kiểm tra thuộc tính
08 alert(me.name);
09
10 // Dùng phương thức construtor để kiểm tra đối tượng User
11 alert(me.constructor == User);
12 // Chạy hàm User
13 User("Test");
14
15 // Trong bối cảnh hàm trên từ khóa 'this' không được sét,
16 // mặc định nó có thể được gán cho đối tượng toàn cầu 'window',
17 // nghĩa là bạn có thể truy cập tới thuộc tính name
18 alert(window.name);

Phương thức public

Phương thức public giúp bạn sử dụng nó bên ngoài đối tượng, bạn có thể tạo phương thức public bên ngoài đối tượng thông qua một đối tượng trung gian đó là prototype. Ví dụ:

01 // Tạo cấu trúc đối tượng User
02 function User(name, age) {
03   this.ten = name;
04   this.tuoi = age;
05 }
06 // Thêm phương thức getName cho đối tượng User
07 User.prototype.getName = function () {
08   return this.ten;
09 };
10 // Thêm phương thức getAge cho đối tượng User
11 User.prototype.getAge = function () {
12   return this.tuoi;
13 };
14
15 // Tạo một biến user lưu đối tượng User
16 var user = new User("Bob", 44);
17 // Kiểm tra hai phương thức của đối tượng
18 alert(user.getName());
19 alert(user.getAge());

Bạn có thể thấy prototype thực sự tiện lợi giúp bạn tạo phương thức của đối tượng một cách giễ ràng, và nó được dùng phổ biến để xây dựng ứng dụng javaScript

Phương thức private

Phương thức private được tạo ra bên trong đối tượng điều này làm cho bạn không thể truy cập nó bên ngoài đối tượng, nó tạo sự chặt chẽ cho ứng dụng của bạn, khỏi đụng độ với các đối tượng khác khi bạn phát triển ứng dụng với lượng code lớn. Xem ví dụ sau để hiểu hơn về phương thức private:

01 // Tạo cấu trúc cho đối tượng Classroom
02 function Classroom(students, teacher) {
03   // Tạo một phương thức private hiển thị sinh viên trong lớp
04   function get() {
05     alert(students.join(", "));
06   }
07   // Tạo thuộc tính đối tượng lưu trữ thông tin
08   this.students = students;
09   this.teacher = teacher;
10   // Gọi phương thức get
11   get();
12 }
13
14 // tạo đối tượng Classroom
15 var myclass = new Classroom(["Chiến", "Đinh"], "Thảo");
16 // Kiểm tra phương thức của đối tượng
17 alert(myclass.teacher)
18 // Gọi phương thức private bên ngoài đối tượng
19 myclass.get();

Kết quả ví dụ trên khi gọi phương thức private bên ngoài đối tượng ta nhận được một thông báo lỗi là đối tượng Classroom không có phương thức get()

phương thức privileged

Đây là phương thức được tạo bên trong đối tượng và bạn có thể truy cập nó bên ngoài đối tượng, thực ra nó là một hàm "nặc danh" được lưu vào một thuộc trong đối tượng. Xem ví dụ sau để hiểu rõ hơn điều này:

01 // Tạo cấu trúc đối tượng User
02 function User(name, age) {
03   // Tạo biến lưu thông tin năm sinh
04   var year = (new Date()).getFullYear() - age;
05   // Tạo phương thức Privileged trả về năm sinh
06   this.getYearBorn = function () {
07     return year;
08   }
09 }
10
11 // Tạo đối tượng User
12 var user = new User("Bob", 44);
13 // Kiểm tra phương getYearBorn
14 alert(user.getYearBorn());

Phương thức static

Trước kia khi tôi tìm hiểu về kỹ thuật tạo phương thức static, tôi đã bị bất ngờ bởi kết quả mà nó đem lại. Trước tiên chúng sẽ ta cùng xét một số trường hợp sử dụng đối tượng trong javaScript với phương thức public. Bạn  sẽ sử dụng lại ví dụ đã trình bày ở phần phương thức public.

Nếu bạn gán đối tượng user cho một biến user2 và kiểm tra các phương thức và thuộc tính của user trên user2 thì thực chất user và user2 là một, cùng là đối tượng User vì mọi thay đổi trên user hay user2 đều ảnh hưởng lẫn nhau. Ví dụ:

01 var user = new User('Tí',100);
02 var user2 = user;
03 alert(user2.getName()); // Kết quả: Tí
04
05 // Thay đổi thuộc tính 'ten' trên user2
06 user2.ten = 'Tẻo';
07 alert(user2.getName()); // Kết quả: Tèo
08 alert(user.getName()); // Kết quả: Tèo
09
10 // Nếu tạo thêm thuộc tính cho đối tượng user2
11 user2.interest = 'web';
12 alert(user.interest); // Kết quả: web

Nếu bạn muốn tạo ra đối tượng User khác thì bạn phải gọi lại và không thể thừa kế được giá trị gì từ đối tượng trước đã tạo, bạn buộc phại gọi lại đối tượng với tham số hay các giá trị cần thiết. Ví dụ:

01 var user = new User('Tí',100);
02 var user3 = new User('Tí',100);
03 alert(user3.getName()); // Tí
04
05 // Thay đổi thuộc tính 'ten' trên user3
06 user3.ten = 'Tèo';
07 alert(user3.getName()); // Tèo
08 alert(user.getName()); // Tí
09
10 // Nếu tạo thêm thuộc tính cho đối tượng user3
11 user3.interest = 'web';
12 alert(user.interest); // Kết quả: thuộc tính không xác định
13 alert(user3.interest); // Kết quả: web

Tuy khi thêm hay thay đổi user3 thì không ảnh hưởng gì đến user nhưng bạn không thừa kế được những giá trị đã được tạo ra hay thay đổi từ user mà bạn phải khai báo lại nó. Vấn đề này nảy sinh ra một kỹ thuật trong javaScript mà người ta gọi nó là phương thức static. Xem ví dụ sau để hiểu rõ điều này:

01 // Tạo phương thức static cloneUser tới đối tượng User
02 User.cloneUser = function (user) {
03   // Tạo và trả về một đối tượng user mới
04   return new User(
05   // Nhân bản những phương thức hay thuộc tính đối tượng user
06   user.getName(),
07   user.getAge());
08 };
09
10 var user = new User('Tí', 100);
11 // Sử dụng phương thức cloneUser nhân bản đối tượng user
12 var other = User.cloneUser(user);
13 alert(other.getName()); // Tí
14
15 // Thay đổi giá trị thuộc tính 'ten' trên other
16 // đối tượng user không đổi
17 other.ten = 'Tèo';
18 alert(other.getName()); // Tèo
19 alert(user.getName()); // Tí
20
21 // Thay đổi giá trị thuộc tính 'ten' trên user.
22 // đối tượng other không đổi
23 user.ten = 'Tùng';
24 alert(user.getName()); // Tùng
25 alert(other.getName()); // tèo
26
27 // Nhân bản đối tượng user một lần nữa
28 var other1 = User.cloneUser(user);
29 alert(other1.getName()); // Tùng
30
31 // Nhân bản đối tượng other
32 var other2 = User.cloneUser(other);
33 alert(other2.getName()); // Tèo

Điều này thực sự hữu dụng nếu bạn phát triển ứng dụng lớn nhưng cũng có thể giễ gây nhầm lẫn nếu bạn mới làm quen với kỹ thuật này. Khi bạn thực hiện coding một dự án nào đó bạn nên nghĩ ngay tới việc coding làm sao đoạn code bạn có thể dùng lại giễ dàng và có thể phát triển tiếp, nếu mỗi lần dùng lại bạn lại phải tìm hiểu rồi edit nhiều chỗ mới dùng được hay thậm chí phải code lại từ đầu thì quả là phí công sức nếu ứng dụng bạn có một lượng code lớn, đó là vì sao việc coding theo hướng đối tượng là điều nên làm bởi vì ưu điểm của nó thì có lẽ bạn cũng biết, nhưng cũng có thể là không cần thiết với ứng dụng nhỏ và đơn giản, tất cả là tùy ở bạn, tôi mong nhận được sự góp ý của tất cả các bạn có cùng chung sở thích.

 

Các tin tức khác