Hoc Prototype

Giới thiệu sửa

Đây là một bài viết hay và bổ ích về thư viện Prototype - một thư viện Javascript rất nổi tiếng. Prototype được sử dụng làm phần core cho nhiều thư viện javascript open source như: MooTool, Prototype Window, ...

Tôi đọc được bài viết này từ VNRuby.org (trang web của hội Ruby Việt Nam). Rất cảm ơn tác giả Giang Trần đã đóng góp một bản dịch thật hay và dễ hiểu cho những lập trình viên Việt Nam. Bạn có thể đọc Bản gốc của bài viết này tại: http://vnruby.org/repos/prototype.js.vi/prototype.js.vi.html

Mục có liên quan sửa

Advanced JavaScript guide.[1]

Các hàm tiện ích sửa

Thư viện này mang đến rất nhiều các đối tượng và các hàm tiện ích đã được định nghĩa sẵn. Mục tiêu chủ yếu của các hàm này là nhằm giúp bạn đỡ phải lập đi lặp lại việc đánh máy và các thành ngữ.

Đối tượng Ajax sửa

Hàm tiệc ích được đề cập phía trên là rất tốt nhưng, sự thật là nó không phải là cách tốt nhất để làm công việc này. Bạn có thể tự viết nó hoặc có thể có nhưng hàm tương tự trong mã lệnh của bạn. Nhưng những hàm đó chỉ là phần nổi của tảng băng mà thôi.

Tôi chắc chắn là bạn thấy hứng thú với prototype.js là vì khả năng hỗ trợ AJAX của nó. Bây giờ hãy cùng giải thích vì sao thư viện này sẽ làm cho bạn thấy thoải mái hơn khi bạn cần thực hiện các cấu trúc login của AJAX.

Đối tượng Ajax là một đối tượng được định nghĩa sẵn, được tạo bởi thư viện nhằm gói gọn và làm đơn giản những đoạn mã khó hiểu khi viết các chức năng AJAX. Hàm này chứa một số lớp cung cấp các cấu trúc AJAX được gói gọn lại. Nào, hãy xem thử qua một số trong chúng.

Mánh khóe với String sửa

Strings là một đối tượng rất mạnh. Prototype.js tận dụng sức mạnh và nâng nó lên một tầm cao khác về chất lượng.

Thay thế Strings:
Mẫu sẵn có của Strings:

Sử dụng lớp Ajax.Request sửa

Sử dụng lớp Ajax.Updater sửa

"?" và □ là cái gì? sửa

Khi bạn viết mẫu thử 1 vài script để cập nhật trang bằng cách sử dụng đối tượng Ajax.Updater, và nó hoạt động rất tốt. Nó vẫn tốt cho đến khi bạn chạy script của mình với dữ liệu thật đột nhiên trong các chuỗi cập nhật xuất hiện những dấu '?' và '□' hay những dấu hiệu lạ khác tại những chỗ không phải là tiếng Anh chuẩn.

Điều nghi ngờ đầu tiên của bạn là prototype.js. Nhưng khoang hãy đổ lỗi cho nó. Hãy hỏi xem là bạn đã thật sự hiểu về mã kí tự(character encoding), mã trang và cách mà trình duyệt xử lý nó hay chưa? Sau đây tôi sẽ trình bày một cách rõ ràng về vấn đề này, và cho bạn một số gợi ý để bạn có thể bắt đầu chỉnh sửa cho phù hợp với yêu cầu của mình.

Đơn giản là hãy làm theo cách sau: hãy cho trình duyệt những gì mà nó muốn bạn cho nó. Ví dụ: nếu bạn cập nhật trang chứa các kí tự Unicode/UTF-8 thì hãy cho trình duyệt biết về điều ấy. Hãy bắt đầu với 1 trường hợp đơn giản khi bạn cập nhật trang với văn bạn ở dạng HTML tĩnh nằm trên server. Khi tạo ra tập tin đó, tùy vào công cụ biên tập của bạn mà rất có thể tập tin sẽ được lưu ở dạng ANSI(non-Unicode). Điều này là mặc định ở 1 số công cụ biên tập, đặc biệt là các công cụ biên tập mã nguồn vì kích thước tập tin sẽ nhỏ hơn, và cũng rất hiếm để có kí tự Unicode trong mã nguồn. Giả sử bạn có tập tin sau tên là static-content.html trên server. Bạn lưu nó dưới dạng ANSI.

<div>Hi there, José. Yo no hablo español.</div>

Trang của bạn sẽ cập nhật bằng việc sử dụng vài dòng mã sau đây.

<script>
   function updateWithFile(){
      var url = 'static-content.html';
      var pars = ;
      var myAjax = new Ajax.Updater('placeholder', url, {method: 'get', parameters: pars});
   }
</script>

 <div id="placeholder">(this will be replaced)</div>
 <input id="btn" value="Test With Static File" onclick="updateWithFile()" type="button"/>
 

Khi bạn nhấn nút, tập tin sẽ được gọi nhưng những kí tự không phải tiếng Anh sẽ được thay thế bằng dấu ? và những kí tự khác. Nó sẽ trông giống như "Hi there, Jos?. Yo no hablo espa?ol." hay "Hi there, Jos?Yo no hablo espa?", tùy vào trình duyệt của bạn. Trong trường hợp này thì chỉ cần lưu tập tin lại với dạng phù hợp. Hãy lưu nó lại ở dạng UTF-8 và chạy lại. Bạn sẽ thấy rằng nó sẽ hiển thì đúng(bạn nhớ refresh lại trình duyệt để loại bỏ cache)

Nếu HTML mà bạn dùng không phải là dữ liệu tính, và nếu nó được tạo ra bởi một số framework (như ASP.NET, PHP, Ruby hay Perl,), hãy chắc chắn rằng mã tạo ra HTML phải ở dạng phù hợp bao gồm cả HTTP headers. Mỗi hệ cơ sở đều có cách riêng để giải quyết vấn đề này, nhưng đều tương tự nhau cả.

Ví dụ trong ASP.NET bạn có thể xác lập trong web.config

<globalization requestEncoding="utf-8" responseEncoding="utf-8" />

Trong ASP 3.0 bạn sử dụng dòng mã sau.

Response.CodePage = 65001
Response.CharSet = "utf-8" 

Trong PHP, cú pháp để thêm vào header trông như sau.

<?php header('Content-Type: text/html; charset=utf-8'); ?>

Trong trường hợp, mục đích cuối cùng của bạn là để có HTTP header sau gởi cùng với yêu cầu.

Content-Type: text/html; charset=utf-8 

Chúng ta sử dụng UTF-8 trong ví dụ phía trên, nhưng nếu bạn cần những thiết lập khác bạn có thể dễ dàng thay đổi.

Enumerating... Wow! Damn! Wahoo! sửa

Tủ sách mở Wikibooks Jump to: navigation, search

Chúng ta đã rất quen thuộc với vòng lặp. Bạn biết đấy, tạo ra một mảng, thêm vào nó các phần tử cùng type, tạo một cấu trúc lặp (for, foreach, while, repeat, ...), truy cập mỗi phần tử một cách tuần tự, bằng số chỉ vị trí của nó, sau đó thì thao tác gì đấy với các phần tử.

Khi bạn nghĩ về nó, hầu hết bạn đều có một mảng trong mã lệnh của bạn, có nghĩa rằng bạn sẽ sử dụng mảng đó trong 1 vòng lặp sớm hay muộn. Sẽ không tốt hơn sao nếu đối tượng mảng có nhiều chức năng hơn để thao tác với các vòng lặp này. Và đúng thế, nó sẽ hay hơn rất nhiều. Và nhiều ngôn ngữ lập trình cung cấp những chức năng như thế cho các mảng hoặc những cấu trúc tương tự (như là tập hợp, danh sách)

Và, ngỡ ra rằng prototype.js cho chúng ta đối tượng Enumerable, đối tượng này khởi tạo một loạt các mánh khóe giúp chúng ta thao tác với dữ liệu lặp. Thư viện prototype.js tiến xa hơn 1 bước nữa và mở rộng lớp Array với tất cả các phương thức của Enumerable.

Vòng lặp, theo type của Ruby sửa

Trong javascript chuẩn, nếu bạn muốn thể hiện tuần tự các phần tử của một mảng, bạn phải viết rất đầy đủ như sau.

<script>
   function showList(){
      var simpsons = ['Homer', 'Marge', 'Lisa', 'Bart', 'Meg'];
      for(i=0;i<simpsons.length;i++){
         alert(simpsons[i]);
      }
   }
</script>
<input type="button" value="Show List" onclick="showList();" > 

Với người bạn mới, prototype.js, bạn có thể viết lại vòng lặp này như sau.

function showList(){
   var simpsons = ['Homer', 'Marge', 'Lisa', 'Bart', 'Meg'];
   simpsons.each( function(familyMember){alert(familyMember);});
}

Bạn có thể nghĩ rằng "cần gì phải làm to chuyện, chỉ là nồi cũ vung mới thôi mà" Hãy khoan đã nào, ở ví dụ trên, đúng là chẳng có gì đặc biết cả. Sẽ chẳng có gì là thay đổi với một ví dụ đơn giản. Nhưng dù sao thì hãy cứ đọc tiếp đi nào.

Trước khi chúng ta tiếp tục, bạn có thấy là hàm này được truyền dưới dạng tham số cho phương thức each hay không? Hãy bắt đầu thay nó bằng một hàm lặp.

Vài điều về mảng sửa

Như chúng ta đã đề cập ở trên, việc tất cả các phần tử trong một mảng có cùng một type, cùng thuộc tính và phương thức là rất thông dụng. Hãy xem làm thế nào chúng ta có thể tận dụng ích lợi của các hàm lặp với các mảng mới này. Tìm một phần tử phù hợp với tiêu chuẩn.

<script>
    function findEmployeeById(emp_id){
       var listBox = $('lstEmployees')
       var options = listBox.getElementsByTagName('option');
       options = $A(options);
       var opt = options.find( function(employee){return (employee.value == emp_id);});
       alert(opt.innerHTML); // hiển thị tên nhân viên
    }
</script>
<select id="lstEmployees" size="10" >
   <option value="5">Buchanan, Steven</option>
   <option value="8">Callahan, Laura</option>
   <option value="1">Davolio, Nancy</option>
   </select>
<input type="button" value="Find Laura" onclick="findEmployeeById(8);" > 

Bây giờ hãy thêm 1 mánh nữa nào. Xem làm sao chúng ta có thể lọc ra các phần tử trong các mảng, và chỉ lấy về 1 thành viên mong muốn của mỗi phần tử.

<script>
    function showLocalLinks(paragraph){
       paragraph = $(paragraph);
       var links = $A(paragraph.getElementsByTagName('a'));
       //find links that do not start with 'http'
       var localLinks = links.findAll( function(link){
                                                      var start = link.href.substring(0,4);
                                                      return start !='http';
                                                      });
       //now the link texts
       var texts = localLinks.pluck('innerHTML');
       //get them in a single string
       var result = texts.inspect();
       alert(result);
    }
</script>

 <p id="someText">
    This <a href="http://othersite.com/page.html">text</a> has a <a href="#localAnchor">
    lot</a> of <a href="#otherAnchor">links</a>.
    Some are <a href="http://wherever.com/page.html">external</a> and some are <a href="#someAnchor">local</a>
 </p>
 <input type=button value="Find Local Links" onclick="showLocalLinks('someText')">
 

Cần phải luyện tập nhiều thì mới có thể hoàn toàn quen thuộc với cú pháp này được. Hãy xem qua Enumerable và Array để tham khảo toàn bộ các hàm.

Tài liệu tra cứu cho prototype.js sửa

  • Phần mở rộng cho các lớp JavaScript
Một trong số các cách mà thư viện prototype.js sử dụng để thêm các chức năng đó là mở rộng các lớp đã có sẵn của JavaScript.
Thư viện hỗ trợ bạn bằng cách cung cấp nhiều đối tượng được khởi tạo để hỗ trợ cho thiết kế hướng đối tượng và hỗ trợ các chức năng tổng quát.
Đối tượng này đóng vai trò gốc rễ cho các lớp khác trong thư viện. Nó không có các thuộc tính hay phương thức nào. Các lớp được định nghĩa trong đối tượng này cũng được xem như là các lớp trừu tượng (abstract class)truyền thống.
Đối tượng này đóng vai trò gốc rễ cho các lớp khác trong thư viện. Nó không có các thuộc tính hay phương thức nào. Các lớp được định nghĩa trong đối tượng này cũng được xem như là các lớp trừu tượng (abstract class)truyền thống.