324-Mang Trong JavaScript

16
M ng trong JavaScript Mảng trong JavaScript Vũ Mạnh Cường Email: [email protected] Nội dung Array và struct trong JavaScript Chú ý Khi copy các mã JavaScript để chạy phải thay thế các dấu nháy kép “” cho đúng nếu không sẽ không chạy được. 1

Transcript of 324-Mang Trong JavaScript

M ng trong JavaScriptả

Mảng trong JavaScriptVũ Mạnh CườngEmail: [email protected]

Nội dungArray và struct trong JavaScript

Chú ýKhi copy các mã JavaScript để chạy phải thay thế các dấu nháy kép “” cho đúng nếu không sẽ không chạy được.

1

M ng trong JavaScriptả

Mục lục1.Mảng trong JavaScript........................................................................................................................3

Có bao nhiêu cách viết mảng trong JavaScript?................................................................................3Cách 1: Sử dụng lớp 'Array'..........................................................................................................3Cách 2: Sử dụng cặp ngoặc vuông '[]'...........................................................................................3Cách 3: Sử dụng cặp ngoặc bao '{}'..............................................................................................4

Sự khác nhau giữa các cách viết mảng..............................................................................................4Sử dụng mảng để viết lớp..................................................................................................................5

2.Lớp Array............................................................................................................................................6Cách sử dụng.....................................................................................................................................6

Khởi tạo mảng như tạo một object trong C++, C# hay Java........................................................6Lấy kích thước (tổng số phần tử) của mảng.................................................................................6Nối các phần tử trong mảng thành 1 chuỗi dùng hàm join của Array..........................................6

Các chức năng của Array...................................................................................................................6Giống như 1 mảng thông thường..................................................................................................6Stack..............................................................................................................................................7Queue............................................................................................................................................8Hashtable......................................................................................................................................9

3.Tạo lớp Map đặc biệt.........................................................................................................................11Cách dùng........................................................................................................................................11

Khởi tạo.......................................................................................................................................11Gán giá trị....................................................................................................................................11Lấy 1 phần tử..............................................................................................................................12Tìm kiếm 1 phần tử.....................................................................................................................13Xử kết quả trả về.........................................................................................................................13Xóa 1 phần tử..............................................................................................................................14

Benchmark.......................................................................................................................................14Mã nguồn (file SMap.js – 1.43KB/ 61 lines)..................................................................................15

2

M ng trong JavaScriptả

1. Mảng trong JavaScript

➢ Có bao nhiêu cách viết mảng trong JavaScript?Có 3 cách như sau:

Cách 1: Sử dụng lớp 'Array'Vì Array là 1 object nên phải dùng từ khóa 'new' để tạo mảng.// Khai báo mảngvar arr = new Array();

Nếu muốn đưa giá trị vào các phần tử của mảng thì hãy khai báo như sau:// Khai báo mảngvar arr = new Array(“xin chào”, 100, “bạn là ai thế?”, 0.911);

// Để kiểm tra các giá trị có trong arr thì dùng đoạn mã sau:for (var x in arr) alert(arr[x]); // x là index, arr[x] là value

// Hoặc tương đương với đoạn mã trên:for (var i=0; i<arr.length; i++) alert(arr[i]);

// Cả 2 lệnh 'for' ở trên đều cho cùng 1 kết quả.

Có thể đưa mọi loại giá trị vào trong mảng Array.Chi tiết về lớp Array xem phần 2. Lớp Array.

Cách 2: Sử dụng cặp ngoặc vuông '[]'Thực ra đây là một kiểu viết khác của lớp Array. Khi khai báo mảng bằng cặp ngoặc vuông '[]' thì cũng sử dụng được các phương thức có trong lớp Array (xem phần 2. Lớp Array).// Khai báo mảngvar arr = [];

Nếu muốn đưa giá trị vào các phần tử của mảng thì hãy khai báo như sau:// Khai báo mảngvar arr = [“xin chào”, 100, “bạn là ai thế?”, 0.911];

// Để kiểm tra các giá trị có trong arr thì dùng đoạn mã sau:for (var x in arr) alert(arr[x]); // x là index, arr[x] là value

// Hoặc tương đương với đoạn mã trên:for (var i=0; i<arr.length; i++) alert(arr[i]);

// Cả 2 lệnh 'for' ở trên đều cho cùng 1 kết quả.

Có thể đưa mọi loại giá trị vào trong mảng Array.Vì '[]' giống lớp 'Array' nên xem phần 2. Lớp Array để biết về khả năng của '[]'.

3

M ng trong JavaScriptả

Cách 3: Sử dụng cặp ngoặc bao '{}'Cách này hay dùng khi muốn tạo 1 bảng hash (hash-map):// Khai báo mảngvar arr = {item1: “xin chào”, item2: 100, item3: “bạn là ai thế?”, item4: 0.911};

// Để sử dụng lệnh 'for' để duyệt mảng hash thì chỉ có 1 cách thôi:for (var x in arr) alert(arr[x]); // x là key, arr[x] là value

Khai báo tổng quát của mảng hash như sau:// Khai báo chungvar arr1 = {key1: value1, key2: value2, ...};

// Hoặc tách các cặp (key, value) ra từng dòng riêng rẽ:var arr2 = {

key1: value1,key2: value2,...

}

// Khi duyệt mảng hash thì dùng 'for (var x in...for (var x in arr) {

// Xử lý x ở đây}

// Lấy từng phần tử của mảng hash qua key của nó như sau:var value = arr[key];

Tuy nhiên mảng hash không sử dụng được các phương thức của lớp Array. Bù lại, cách viết này rất lý thú khi tạo lớp.

➢ Sự khác nhau giữa các cách viết mảngSo sánh qua bảng sau:

Nội dung so sánh Array [] {}Phân loại Mảng+Hash Mảng+Hash HashHỗ trợ các phương thức duyệt mảng như: push, pop, shift... (nhiều đấy, google để tìm nhé)

Có Có Không

for (var x in array) Có Có Cófor (var i=0; i<array.length; i++) Có Có KhôngLấy kích thước bằng: array.length Có Có KhôngHỗ trợ viết lớp Không Không Có

4

M ng trong JavaScriptả

➢ Sử dụng mảng để viết lớpViệc dùng mảng để viết lớp chỉ áp dụng cho cách khai báo thứ 3 (xem lại mục trên).

Có thể khai báo lớp như sau:// Khai báo lớp không dùng mảng hashfunction Class() {

this.thuoc_tinh1 = 'thuộc tính1'; // giá trị tùy ýthis.thuoc_tinh2 = 1000; // giá trị tùy ý

/* Khai báo phương thức 1 cho lớp Class */this.phuong_thuc1 = function(){

// xử lý ở đâyalert(this.thuoc_tinh2);alert(this.thuoc_tinh1);

}

/* Khai báo phương thức 2 cho lớp Class */this.phuong_thuc2 = function(){

// xử lý ở đây}

}

Nếu dùng mảng hash thì có thể tách riêng phần hàm tạo của lớp với phần khai báo các thuộc tính và các phương thức còn lại như sau:// Khai báo lớp có dùng mảng hashfunction Class() {} // Chỉ là hàm tạo thôi, ko chứa gì cả

/* Khai báo thuộc tính và phương thức của lớp bằng mảng hash */Class.prototype = {

thuoc_tinh1: 'thuộc tính1', // giá trị tùy ýthuoc_tinh2: 1000, // giá trị tùy ýphuong_thuc1: function() {

// xử lý ở đâyalert(this.thuoc_tinh2);alert(this.thuoc_tinh1);

},phuong_thuc2: function(param1, param2...) {

// xử lý ở đây},

}

Lưu ý là vì dùng mảng nên phải có dấu phẩy ',' để ngăn cách các thuộc tính và phương thức của lớp. Khi dùng mảng hash thì ko cần dùng đến khai báo 'this' nhưng khi tham chiếu thì phải dùng 'this'.Hoàn toàn có thể kết hợp 2 cách khai báo lớp ở trên khi viết lớp.

5

M ng trong JavaScriptả

2. Lớp ArrayLớp Array trong JavaScript rất mạnh. Nó làm được mọi thứ:

✗ Mảng✗ Stack✗ Queue✗ Hashtable

➢ Cách sử dụng

Khởi tạo mảng như tạo một object trong C++, C# hay Java// Array trong JavaScript là 1 object// Đặt tên Array giống tên biếnvar arr = new Array();hoặc// Tạo mảng có kích thước 100var arr = new Array(100);Nếu biết trước kích thước mảng thì khai báo theo cách thứ 2 sẽ chạy nhanh hơn.Ko phải xóa bộ nhớ cho mảng vì JavaScript có bộ dọn dẹp riêng (giống Java hoặc C#).

Lấy kích thước (tổng số phần tử) của mảngvar size = arr.length;

Nối các phần tử trong mảng thành 1 chuỗi dùng hàm join của ArrayKhi dùng Array như 1 Hashtable thì ko dùng được hàm join.// Muốn ngăn các phần từ bằng chuỗi gì thì đặt chuỗi đó vào giữa// 2 dấu nháy képvar s = arr.join(“”);

➢ Các chức năng của Array

Giống như 1 mảng thông thường// Có thể gán mọi giá trị cho Array// vì trong JavaScript không phân biệt kiểu dữ liệuarr[i] = value;

Sử dụng như mảng thông thường:arr[i] = arr[i+1]; ...

Ví dụ:<html><title>Array</title><head><script language=”JavaScript”>// Khai báo mảng ko xác định kích cỡ

6

M ng trong JavaScriptả

var arr = new Array();

// Gán giá trị cho mảngarr[0] = 100;arr[1] = “Array”;arr[2] = 57.98;arr[5] = true;

// Để nối các phần tử trong mảng dùng var s = arr.join(“ - ”);alert(“Mảng arr = [”+s+”]”);</script></head><body></body></html>

StackArray cung cấp 2 phương thức là push và pop để thực hiện nhiệm vụ của Stack.// Khai báo stackvar stack = new Array();

// Thêm 1 phần tử vào stack// value là dữ liệu bất kỳ cần đưa vào stackstack.push(value);

// Lấy 1 phần tử từ stackvar element = stack.pop();

Ví dụ:<html><head><title>Stack</title><script language=”JavaScript”>// Tạo stackvar stack = new Array();

// Thêm phần tử vào stackstack.push(“Value 1”);stack.push(“Value 2”);stack.push(“Value 3”);

// Sử dụng log để hiển thị stackvar log = “stack = [”+stack.join(“ -> ”)+”]\n”;

// Lấy dữ liệu từ stack// Ko đặt stack.length trong vòng for vì sau// mỗi vòng lặp kích thước stack sẽ thay đổivar max = stack.length;for (var i=0; i<max; i++)

7

M ng trong JavaScriptả

log += “pop: ”+stack.pop()+”\n”;

// stack sau khi lấy hết dữ liệulog += “stack = [”+stack.join(“ - ”)+”]”;

// Hiển thị stackalert(log);</script></head><body></body></html>

QueueArray cung cấp 2 phương thức làm nhiệm vụ của Queue là push và shift.// Khai báo queuevar queue = new Array();

// Thêm 1 phần tử vào stack// value là dữ liệu bất kỳ cần đưa vào queue.// Giống y trang stack, huh?queue.push(value);

// Lấy 1 phần tử từ queuevar element = queue.shift();

Ví dụ:<html><head><title>Queue</title><script language=”JavaScript”>// Tạo queuevar queue = new Array();

// Thêm phần tử vào queuequeue.push(“Value 1”);queue.push(“Value 2”);queue.push(“Value 3”);

// Sử dụng log để hiển thị queuevar log = “queue = [”+queue.join(“ -> ”)+”]\n”;

// Lấy dữ liệu trong queue// Ko đặt queue.length trong vòng for vì sau// mỗi vòng lặp kích thước queue sẽ thay đổivar max = queue.length;for (var i=0; i<max; i++)

log += “shift: ”+queue.shift()+”\n”;

// Queue sau khi hết dữ liệu

8

M ng trong JavaScriptả

log += “queue = [”+queue.join(“ -> ”)+”]”;

// Hiển thị queuealert(log);</script></head><body></body></html>

HashtableThay chỉ số (số thứ tự các phần tử trong Array) bằng chuỗi sẽ được bảng hash.// Tạo bảng hashvar hashtable = new Array();

// Gán giá trị (key, value) cho bảng hashhashtable[key] = value;

Việc tạo bảng hash chỉ được 1 mức:hashtable[key1][key2] = value; // error vì có 2 mứchashtable[key1] = value; // okhashtable[key2] = value; // ok

Khi tạo bảng hash thì ko dùng được phương thức join và thuộc tính length.Để đọc tất cả các (key, value) trong bảng hash ko dùng vòng lặp for như sau:for (var value in hashtable){

// xử lý value ở đây}

Ví dụ:<html><head><title>Hash Table</title><script language=”JavaScript”>// Tạo bảng hashvar hashtable = new Array();

// Thêm giá trị vào bảng hashhashtable[“key1”] = “value1”;hashtable[“key2”] = 2;

// Hiển thị từng value theo keyalert(hashtable[“key1”]);alert(hashtable[“key2”]);alert(hashtable[“key3”]); // kq: undefined

// Hiển thị tất cả các giá trị trong bảng hashvar log = “”;for (var value in hashtable)

9

M ng trong JavaScriptả

log += value+”; ”alert(log);</script></head><body></body></html>

10

M ng trong JavaScriptả

3. Tạo lớp Map đặc biệtLớp SMap (Special Map) thực hiện giống như lớp Properties trong Java như thế này:

✗ Nhập vào 1 cặp (key, value) cái SMap đó sẽ tự động ghi lại theo mức như sau level1.level2...levelN = value

✗ Khi lấy giá trị của SMap có thể lấy bằng cách phức: map[level1][level2]...[levelN]✗ Một mức (level) có thể có nhiều giá trị.

Ví dụ:staff là 1 bản ghi chứa các thuộc tính (name, age, company) sẽ được ghi lại trong SMap theo dạngSMap = {staff: {name, age, company},...};

✗ Điều lý thú ở SMap là nó chứa mảng của mảng.✗ Lý do tạo ra SMap là vì JavaScript ko cho phép khai báo theo kiểu:

var map = new Array();map[staff][name] = “Vũ Mạnh Cường”;// errormap[staff][age] = 25; // errormap[staff][company] = “abc-soft”; // error

Ko nhiều nhưng trong một số tình huống cần dùng đến SMap.

➢ Cách dùng

Khởi tạoKhởi tạo SMap như 1 object thông thường trong JavaScriptvar map = new SMap();

Gán giá trịCó 2 cách

✔ Gán giá trị qua phương thức push(key, value) của SMap

map.push(key, value);

key là 1 chuỗi (có thể là UNICODE hoặc mã kỹ tự khác, tùy ý) có dạng như saulevel1.level2...levelNGiữa các mức của key có dấu chấm '.'

Ví dụ 1// Lưu thông tin 1 nhân viênmap.push(“cuongvm.tên”, “Vũ Mạnh Cường”);map.push(“cuongvm.tuổi”, 25);map.push(“cuongvm.côngty”, “abc-soft”);

Trong ví dụ 1 chỉ có 2 level: “cuongvm” là level1; “tên”, “tuổi”, “côngty” là level2.

Số lượng level là ko hạn chế và các bản ghi có thể khác cấu trúc tùy thích.

11

M ng trong JavaScriptả

Ví dụ 2// Lưu thông tin 1 nhân viênmap.push(“cuongvm.tên”, “Vũ Mạnh Cường”);map.push(“cuongvm.tuổi”, 25);map.push(“cuongvm.côngty”, “abc-soft”);// Lưu thông tin công tymap.push(“abc-soft.tên”, “Công ty phần mềm ABC”);map.push(“abc-soft.lĩnh-vực”, “Gia công phần mềm”);

Trong ví dụ 2, “cuongvm” và “abc-soft” là 2 bản ghi có cấu trúc khác nhau.

✔ Gán giá trị trực tiếp qua thuộc tính SMap.arrayTrong SMap có hai lọai phần tử: Array và value. Các level trung gian là 1 Array, còn value (chỉ duy nhất các lá) là những gì không phải là Array như chuỗi, số, giá trị boolean, object,...Vì level trung gian là Array nên có thể gán giá trị trực tiếp cho nó. Tuy nhiên việc gán giá trị cho level trung gian chỉ thực hiện được khi level đó đã tồn tại, nếu chưa tồn tại sẽ bị lỗi.

Ví dụ// Giả sử trong SMap đã tồn tại bản ghi “cuongvm” như ở trên.// Do nhu cầu, cần bổ sung thông tin về công việc cho anh// chàng này như sau: “cuongvm.côngviệc”map.array[“cuongvm”][“côngviệc”] = “Lập trình viên”;

Cách này đơn giản hơn là dùng dấu chấm '.' nhưng chỉ thực hiện được khi “cuongvm” là 1 nút trung gian.

Lấy 1 phần tửCó 2 cách

✔ Lấy qua hàm get(key) của SMap

var result = map.get(key);

Ví dụ// Nối tiếp các ví dụ bên trênvar name = map.get(“cuongvm.tên”); // name = “Vũ Mạnh Cường”var nhan_vien = map.get(“cuongvm”); // Array// nhan_vien = cuongvm{“Vũ Mạnh Cường”, 25, “abc-soft”}

✔ Lấy trực tiếp qua thuộc tính SMap.array

var result = map.array[level1][level2]...[levelN];

Ví dụ

12

M ng trong JavaScriptả

var name = map.array[“cuongvm”][“tên”];// name = “Vũ Mạnh Cường”var nhan_vien = map.array[“cuongvm”]; // Array// nhan_vien = cuongvm{“Vũ Mạnh Cường”, 25, “abc-soft”}

Trong trường hợp ko chắc chắn kết quả trả về là Array hay value thì cần kiểm tra nó. Chi tiết nói trong phần: Xử lý kết quả trả về.

Tìm kiếm 1 phần tửTìm 1 phần tử chính là lấy 1 phần tử trong SMap. Xem trong phần Lấy 1 phần tử.

Xử kết quả trả vềCó 3 lọai giá trị trả về khi lấy (hoặc tìm) 1 phần tử trong SMap

✗ Array (level trung gian)✗ null✗ value (các giá trị còn lại)

✔ Kiểm tra kết quả trả vềSau khi lấy 1 phần tử trong SMap mà ko rõ nó thuộc lọai nào thì làm như sau:var result = map.get(“level1.level2...levelN”);// Tương đương:// var result = map.array[level1][level2]...[levelN];

if (result == null){// Không tìm thấy key này trong SMap

} else if (result instanceof Array){// Xử lý mảng result// Toán tử instanceof giống instanceof trong Java

} else{// Xử lý giá trị: mọi thứ không phải là Array

}

✔ Duyệt tất cả các nội dung của 1 bản ghiKhi muốn xử lý tòan bộ các trường của 1 bản ghi làm như sau:for (var field in record){

// Xử lý từng field ở đây}

(xem thêm phần Array -> Hashtable)

Ví dụ// Nối tiếp các ví dụ bên trên// Giả sử đã tồn tại bản ghi sau:// cuongvm{“Vũ Mạnh Cường”, 25, “abc-soft”}var record = map.array[“cuongvm”]; // hoặc map.get(“cuongvm”);var kq = “”; // kết quả

13

M ng trong JavaScriptả

for (var field in record)kq += field+”\n”;

// In kết quả ra màn hìnhalert(kq);

=> Kết quả sau khi chạy ví dụ trên:

Vũ Mạnh Cường25abc-soft

Xóa 1 phần tửChỉ có duy nhất 1 cách là xóa trực tiếp qua thuộc tính SMap.array:map.array[level1][level2]...[levelN] = null;

Thực chất là báo cho bộ dọn dẹp của JavaScript biết để thu hồi vùng nhớ chứa giá trị này khi cần (giống như trong Java hoặc C#).

Ví dụ// Nối tiếp các ví dụ bên trênmap.array[“cuongvm”][“tên”] = null;var name = map.array[“cuongvm”][“tên”]; // name = null// Tương đương: var name = map.get(“cuongvm.tên”);

map.array[“cuongvm”] = null;var nhan_vien = map.array[“cuongvm”]; // nhan_vien = null// Tương đương: var nhan_vien = map.get(“cuongvm”);

➢ BenchmarkTest performance cho SMap.

Test 2 chức năng✗ Thời ghi dữ liệu vào SMap✗ Thời gian tìm kiếm dữ liệu

Có 2 test-case✗ Test-case 1: Ghi vào SMap 1000 bản ghi, sau đó tìm bản ghi cuối cùng (bản ghi 999)✗ Test-case 2: Ghi vào SMap 10,000 bản ghi, sau đó tìm bản ghi ở giữa (bản ghi 5000)✗ Bản ghi có dạng như sau: company{name, address, country, field}

Cấu hình máy✗ Pentium 4 CPU 3.00GHz/ 1GB RAM/ WindowsXP SP2

Kết quảFirefox 2

14

M ng trong JavaScriptả

IE 6

Kết luận✗ SMap chạy tốt khi lưu khoảng 1000->2000 bản ghi (cả ghi lẫn tìm kiếm)✗ Array trong Firefox chạy nhanh hơn Array trong IE

➢ Mã nguồn (file SMap.js – 1.43KB/ 61 lines)// Special Map class, by [email protected], Sept-2007.// Feel free to use and distribute without any warranty.function SMap(){

this.array = new Array();

// class attributesthis._el;this._pos;this._keys;this._klen;

15

M ng trong JavaScriptả

// add new (key, value) to SMapthis.push = function(key, value){

if (typeof value == "undefined") return;

// key not foundif (!this.get(key) && (this._pos < this._klen--)){

if (!this._pos) this._el = this.array;for (var i=this._pos, e=null; i < this._klen; i++){

// i-th level keythis._el[this._keys[i]] = new Array();this._el = this._el[this._keys[i]];

}this._el[this._keys[this._klen]] = value;

} else this._el = value; // key found}

// find existing (key, value) from SMapthis.get = function(key){

if (!this._toArray(key)) return null;

// key is emptyif (this._klen < 1) return (this._el=null);

this._el = this.array[this._keys[this._pos]];if (!this._el) return null; // not found

++this._pos;

for (var e=null; this._pos < this._klen; this._pos++){e = this._el[this._keys[this._pos]];

// not foundif (typeof e == "undefined") return null;this._el = e;

}return this._el;

}

// convert key (dot-separated string) to arraythis._toArray = function(key){

this._pos = 0;if (typeof key != "string"){

this._klen = 0;return false;

}this._keys = key.split(".");this._klen = this._keys.length;return true;

}}

16