Tìm hiểu về Collection of Record trong JavaScript

Quản Trị Mạng - Trong bài viết trước, chúng tôi đã giới thiệu với các bạn một vài đặc điểm về mảng 2 chiều – Array 2D trong JavaScript, trong nhiều trường hợp áp dụng khi chúng ta cần giữ thông tin về 1 hoặc nhiều danh sách số lượng chuỗi dữ liệu nhất định, đối tượng Array sẽ là công cụ được sử dụng phổ biến và nhiều nhất.

Ví dụ như sau:

var aNames= [ "Adam", "Bill", "Carl" ]; // create an array

alert( aNames[0] ); // Adam -- look it up by its index number

// iterate through them
for ( var j=0; j< aNames.length; j++ ) {
alert( aNames[j] ); //
}

Nhưng trên thực tế, JavaScript còn hỗ trợ thêm Associative Arrays (hay còn gọi là Maps hoặc Dictionaries), cung cấp thêm cho người sử dụng 1 cách khác để truy cập vào danh sách các đối tượng không qua vị trí, mà là khóa liên kết:

Tìm hiểu về Collection of Record trong JavaScript

Tuy nhiên, tính năng hỗ trợ này không hoạt động giống với những gì mà chúng ta đã biết trước kia:

// this seems reasonable...

var aNames= new Array();
aNames[ "Anderson" ]= "Adam";
aNames[ "Browne" ]= "Bill";
aNames[ "Crawford" ]= "Carl";

alert( aNames[ "Anderson" ] ); // shows Adam (as expected)

// ... but this might not seem reasonable:

alert( aNames.length ); // shows 0 !!! (why not 3?)

Đoạn mã trên có chức năng tạo đối tượng Array, sau đó chèn dữ liệu nothing vào bất cứ thành phần nào trong mảng này. Và những quá trình tiếp theo sẽ tiến hành sau đó: tất cả các biến JavaScript (bao gồm cả Array) sẽ được coi là đối tượng với thuộc tính cơ bản của 1 Object điển hình. Những thuộc tính đó được xây dựng dựa trên các khối lớp hỗ trợ khả năng xử lý, giám sát cặp giá trị của mảng liên kết. Ví dụ như sau:

var mapNames= new Object(); // or: var mapNames= {};
mapNames[ "Anderson" ]= "Adam";
mapNames[ "Browne" ]= "Bill";
mapNames.Crawford = "Carl"; // alternate syntax
mapNames[ 2 ]= "Two";

alert( mapNames.length ); // undefined (it is not an Array)

for ( var j in mapNames ) { // show the keys
alert( j ); // Anderson, Browne, Crawford, 2
}
for ( var j in mapNames ) { // show the data associated with each key
alert( mapNames[j] ); // Adam, Bill, Carl, Two
}

Cặp giá trị key/value thường xuyên được gọi trong phần thuộc tính – Properties của 1 đối tượng. Và đối tượng Object hỗ trợ tùy chọn cho phép người dùng thiết lập, khởi tạo khóa key và giá trị trong cùng 1 thời điểm:

var mapNames= {
"Anderson" : "Adam", // syntax is key:value
"Browne" : "Bill",
"Crawford" : "Carl"
};
for ( var n in mapNames ) { // show the keys and values
alert( n+ "=" + mapNames[n] ); // Anderson=Adam, Browne=Bill, etc...
}

Giá trị key ở phía bên trái và value ở bên phải. Phần value này không nhất thiết phải là string hoặc bất cứ đối tượng nào tương ứng, chỉ cần có sẵn thuộc tính key/value. Một số thông tin hoặc ví dụ tham khảo, các bạn có thể đọc thêm tại đây.

Gán đối tượng thành tham số chức năng:

Chức năng linh hoạt này tỏ ra rất hữu ích trong nhiều trường hợp, 1 trong những số đó là quá trình truyền dữ liệu qua cấu trúc gọi chức năng, tương tự như như cách làm truyền tham số qua tên biến. Ví dụ như sau:

...
DoThat( {color:"Red", font:"Arial" } ); // unnamed object
...
function DoThat( o ) {
alert( o.color ); // shows: Red
alert( o.font ); // shows: Arial
}

Thủ tục gọi lệnh như trên sẽ tạo ra các đối tượng nặc danh - Anonymous (bộ tổ hợp các giá trị key:value), và các cú pháp lệnh được gọi ra có thể truy cập tới phần giá trị trong đối tượng qua tên. Lưu ý rằng nếu khóa key có dạng chuỗi ký tự thì có thể bỏ qua dấu ngoặc kép khi khởi tạo giá trị thuộc tính.

Tạo các mảng Record kết hợp:

Trên thực tế, chúng ta có thể dễ dàng tạo được các đối tượng map một cách nhanh chóng và gán thêm nhiều thuộc tính đi kèm. Tuy nhiên, cách làm này lại có 1 nhược điểm, ví dụ như sau:

var o= {}; // or: var o= new Object();
o.lastName= "Anderson";
o.age= 17;

... later that day ...

o.LastName= "Smith"; // oops, uppercase L

Nếu bạn bỏ lỡ tên của giá trị key bất kỳ, thì sau đó phải gán thêm thuộc tính mới vào đối tượng này. Mặc dù JavaScript có thể kết hợp với các đối tượng map thì không cần phải khai báo trực tiếp, nhưng làm theo cách này sẽ giúp chúng ta giảm thiểu được khá nhiều lỗi.

Trong phần lớn các trường hợp áp dụng trên thực tế, chúng ta có thể thực hiện bằng cách khởi tạo 1 bản ghi đã được định nghĩa sẵn – với cấu trúc đi kèm có chứa toàn bộ thông tin, dữ liệu trong đối tượng đó. Sau đó, sẽ gán các phần thông tin khởi tạo này tới đối tượng, qua đó chúng ta có thể dễ dàng phân loại, quản lý toàn bộ hệ thống thuộc tính có liên quan.

Tại cùng thời điểm đó, có lẽ các bạn sẽ cần thêm cách để khởi tạo giá trị record ban đầu, thiết lập giá trị mặc định, cách cố định... bằng cú pháp JavaScript như sau:

function PersonRec() {
this.sNameLast= ''; // the "this." part is required
this.sNameFirst= '';
this.nAge= 0;
this.fIsParent= false;
this.asChildren= new Array();
}

Ví dụ như trên, chúng ta đã hoàn tất việc khởi tạo đối tượng với những thuộc tính nhất định. Và khi đã tới bước này, các bạn đã có thể nghĩ đến việc coi 1 đối tượng bất kỳ như 1 bản ghi với nhiều trường dữ liệu khác nhau. Đối với những người đã có sẵn nền tảng kiến thức dựa trên C++, thì có thể rất khó khăn trong việc dùng từ khóa function để khởi tạo 1 cấu trúc xây dựng bất kỳ, nhưng lại có thể gây nhầm lẫn nếu trong phần mã còn lại có chứa chức năng hoặc biến constructor. Đoạn mã ví dụ trên không có tham số, nhưng phần mã dưới đây sẽ đảm nhận việc khởi tạo số lượng các biến của tham số, sau đó gán chúng vào trường dữ liệu riêng biệt:

function PersonRec(p1,p2,p3,p4,p5) {
this.sNameLast= (p1 != undefined) ? p1 : '';
this.sNameFirst=(p2 != undefined) ? p2 : '';
this.nAge= (p3 != undefined) ? p3 : -1;
this.fIsParent= (p4 != undefined) ? p4 : false;
this.asChildren=(p5 != undefined) ? p5 : new Array();
}

Nếu như làm như trên, các ký tự hoặc biến thiếu sót sẽ được phát hiện, và các trường tương ứng sẽ dược tự động gán dữ liệu mặc định. Để tạo record, các bạn hãy sử dụng cú pháp như sau:

var rPer1= new PersonRec(); // populated with defaults

var rPer2= new PersonRec( "Anderson", "Adam", 35, true, ["Andy","Al"] ); // all data

var rPer3= new PersonRec( "Browne", "Bill" ); // with some data and some defaults

rPer3.nAge= 43; // update the record
rPer3.sNameFirst= "William"; // update the record

Chức năng xây dựng có thể thực hiện được nhiều hơn việc gán dữ liệu đơn thuần, ví dụ như tính toán dữ liệu của 1 trường dựa vào một số trường khác có liên quan, đọc hoặc chuyển tiếp thông tin từ trang web, lựa chọn dữ liệu từ database... hoặc bất kỳ thao tác nào người dùng muốn thực hiện mỗi khi 1 đối tượng Record được tạo. Bên cạnh đó, các biến dạng record này không cần lưu trữ theo cách thông thường. Cũng như đối với bất kỳ ngôn ngữ lập trình hướng đối tượng nào khác, người dùng có thể tự khởi tạo các phương thức, chức năng được áp dụng riêng đối với từng loại dữ liệu khác nhau. Ví dụ:

function PersonRec(p1,p2) {
this.sNameLast= p1;
this.sNameFirst=p2;
...
//-------------------------------- add some methods; i.e., member functions
this.GetFullName= function() {
return( this.sNameFirst +" "+ this.sNameLast );
};

this.toString= function() {
var s= "Name: " + this.GetFullName() + "\n";
s+= "Age: " + this.nAge + "\n";
if ( this.fIsParent ) {
s+= "Children: " + this.asChildren;
}
return( s );
};
}

Chúng ta có thể dễ dàng thấy rằng thành phần Object.toString() đã có sẵn, nhưng chỉ hiển thị dữ liệu đầu ra theo dạng [Object object], không thực sự hữu ích cho lắm trong nhiều trường hợp, cách này chỉ phù hợp trong để viết các hàm ghi đè như trên, qua đó chúng ta có thể dễ dàng hiển thị dữ liệu trong quá trình debug.

Sử dụng mảng Record kết hợp:

1 đối tượng mẫu chúng ta đã khởi tạo ở đây thường được sử dụng như 1 thành phần trong mảng dữ liệu, tương tự như 1 bản ghi, và đây là khái niệm rất cơ bản về collection. Giả sử rằng chúng ta có 1 chuỗi dữ liệu được hiển thị dưới dạng menu drop – down, và khi người dùng chọn 1 thành phần, hệ thống sẽ tiến hành quá trình xác định trường dữ liệu tương ứng trong form.

Về bản chất, JavaScript sẽ thực hiện quá trình xác định dữ liệu qua AJAX, hoặc phân tích luồng thông tin qua trang web, hoặc đơn giản hơn là từ 1 file duy nhất nào đó. Đơn giản hơn, chúng ta có thể thực hiện quá trình này trước trong phần mã nguồn:

var arPersons = [
new PersonRec("Anderson", "Adam", 35, true, ["Andy","Alice"] ),
new PersonRec("Browne", "Bill", 25, false ),
new PersonRec("Crawford", "Carl", 45, true, ["Caroline"] )
];

Sau khi hoàn tất bước khởi tạo đối tượng mảng của các bản ghi tương ứng, chúng ta có thể dễ dàng “xâu chuỗi” toàn bộ bằng cú pháp JavaScript như sau:

var oCombo= document.getElementById('selectName'); // a <SELECT> element

oCombo.options.length=0; // clear out the box
oCombo.options.length=arPersons.length; // prepare to repopulate

for (var j=0; j<arPersons.length; j++) {
oCombo.options[j].text= arPersons[j].sNameLast;
}

... later, see what's been selected ...

var i= oCombo.selectedIndex;
alert( arPersons[i].sNameFirst +" is "+ arPersons[i].nAge );

Kết quả hiển thị của bảng dữ liệu sẽ có dạng như sau:

Tìm hiểu về Collection of Record trong JavaScript

Tạo chu kỳ hoạt động của các thành phần trong mảng, sau đó hiển thị giá trị các thuộc tính của đối tượng PersonRec như sau:

function BuildOutputTable() {
var sOut="<table border=2>";
sOut +="<tr>";
sOut +="<td>Last Name</td><td>First Name</td><td>Age</td><td># of Kids</td>"
sOut +="</tr>";
for ( var j=0; j<arPersons.length; j++ ) {
var rP= arPersons[j]; // a PersonRec object
sOut += "<tr>";
sOut += "<td>" +rP.sNameLast+ "</td>";
sOut += "<td>" +rP.sNameFirst+ "</td>";
sOut += "<td>" +rP.nAge+ "</td>";
sOut += "<td>" +rP.asChildren.length+ "</td>";
sOut += "</tr>";
}
sOut += "</table>";
return(sOut);
}

Một số bài viết khác có liên quan đến chủ đề của chúng ta ngày hôm nay:

- Objects as associative arrays

- Mastering Javascript Arrays

- Mastering JSON (JavaScript Object Notation)

Chúc các bạn thành công!

Thứ Ba, 25/10/2011 10:00
51 👨 1.982
0 Bình luận
Sắp xếp theo
    ❖ Kiến thức cơ bản