Array trong JavaScript cũng là một loại object. Nhưng array khác object bình thường ở chỗ là:
- Array (mảng) được thiết kế để lưu trữ dữ liệu theo thứ tự.
- Object (đối tượng) bình thường chỉ là tập hợp của các cặp key-value.
Sau đây, mình sẽ tìm hiểu chi tiết về array trong JavaScript.
Khởi tạo array trong JavaScript
Có hai cách để khởi tạo array rỗng là:
- Sử dụng dấu ngoặc vuông [].
- Sử dụng hàm khởi tạo new Array().
Trong đó, cú pháp sử dụng [] là phổ biển hơn cả vì cách này nhanh và ngắn gọn hơn.
Ngoài ra, bạn có thể khởi tạo array trong JavaScript với một số phần tử cho trước:
Khi đó, các phần tử trong mảng được sắp xếp theo thứ tự, phần tử đầu tiên có chỉ số là 0. Phần tử cuối cùng có chỉ số bằng độ dài mảng trừ đi 1 đơn vị.
Để truy cập các phần tử trong mảng, bạn sử dụng arr[index] với index là chỉ số của phần tử:
Bạn cũng có thể thay đổi giá trị của phần tử trong mảng:
Hoặc thêm phần tử mới vào mảng:
Một số đặc điểm của array trong JavaScript
Tổng số phần tử trong mảng được xác định qua thuộc tính length:
Bạn có thể in ra toàn bộ giá trị của mảng:
Giá trị các phần tử trong mảng có thể thuộc bất kỳ kiểu dữ liệu nào:
Tương tự như object, array có thể có hoặc không dùng “dấu phẩy đuôi” – dấu phẩy sau phần tử cuối cùng.
Việc thêm dấu phẩy sau phần tử cuối cùng giúp phần biểu diễn các thuộc tính giống nhau. Qua đó, việc thêm/xóa phần tử trở nên dễ dàng hơn.
Một số phương thức cơ bản của array
Một số phương thức cơ bản của array trong JavaScript là: arr.pop(), arr.push(), arr.shift() và arr.unshift().
► Phương thức arr.pop()
Lấy ra và trả về phần tử cuối cùng của mảng.
► Phương thức arr.push()
Thêm một hoặc nhiều phần tử vào cuối mảng và trả về độ dài mới của mảng.
► Phương thức arr.shift()
Lấy ra và trả về phần tử đầu tiên của mảng.
► Phương thức arr.unshift()
Thêm một hoặc nhiều phần tử vào đầu mảng.
Mối liên hệ giữa array và object
Như mình đã nói ở trên, array về bản chất cũng là object. Cú pháp truy cập phần tử của mảng arr[index] tương tự như cú pháp của object obj[key]. Nói cách khác, index ở array tương đương key của object.
Và khi copy array thì đó cũng là copy qua tham chiếu – tương tự như copy object:
Điều đặc biệt hơn của array so với object là: array lưu trữ dữ liệu theo thứ tự.
JavaScript Engine sẽ cố gắng lưu trữ các phần tử của mảng vào các vùng nhớ liên tiếp nhau. Và tối ưu hóa để làm sao truy cập các phần tử mảng nhanh nhất.
Nhưng tất cả những điều này sẽ không còn đúng nữa, nếu bạn sử dụng array theo kiểu của object, ví dụ:
Cách sử dụng trên không có lỗi cú pháp nhưng không đúng với ý nghĩa khi tạo ra array trong JavaScript.
Mục đích của array là để lưu trữ dữ liệu theo thứ tự. Nếu bạn muốn lưu trữ thuộc tính với key bất kỳ thì hãy sử dụng object thông thường {}.
Duyệt tất cả các phần tử trong mảng
Cách cơ bản nhất để duyệt tất cả các phần tử của mảng trong JavaScript là dùng vòng lặp for với chỉ số:
Kết quả:
Nếu không quan tâm đến chỉ số, bạn có thể dùng vòng lặp for…of cho ngắn gọn hơn:
Ngoài ra, bạn cũng có thể dùng vòng lặp for…in tương tự như cách duyệt tất cả các key trong object:
Cách sử dụng for…in không sai, nhưng có một số vấn đề là:
- Cách này không tối ưu cho duyệt mảng nên thường chậm hơn hai cách trên.
- Đối với một số object dạng “array-like”, ngoài length và chỉ số ra thì “array-like” còn có thêm một số thuộc tính khác nữa. Việc sử dụng for…in sẽ duyệt hết tất cả các thuộc tính (bao gồm dạng số và không phải dạng số). Điều này là không cần thiết.
Nói chung, không nên sử dụng for…in để duyệt hết tất cả các phần tử của array trong JavaScript.
Vấn đề liên quan đến length của array
Thuộc tính length được tự động cập nhật mỗi khi bạn thêm/xóa phần tử trong mảng. Nhưng length không thật sự biểu thị số lượng phần tử trong mảng.
Giá trị của length bằng chỉ số lớn nhất trong mảng cộng thêm 1 đơn vị, ví dụ:
Chú ý: đây chỉ là ví dụ minh họa, bạn không nên sử dụng array theo cách này.
Thuộc tính length là writable. Nghĩa là bạn có thể thay đổi giá trị của thuộc tính length.
Nếu bạn tăng nó lên thì không sao. Nhưng ngược lại, nếu bạn giảm giá trị của length thì mảng sẽ bị cắt ngắn đi:
Trong ví dụ trên, khi bạn giảm length rồi tăng length trở lại, giá trị trước đó trong mảng (letters[2]) không được khôi phục trở lại.
💡 Cách đơn giản nhất để xóa mảng là gán length bằng 0: arr.length = 0.
Vấn đề về cú pháp new Array()
Đây là một cú pháp khác để khởi tạo array trong JavaScript:
Cú pháp trên khởi tạo array với ba phần tử tương tự như sau:
Tuy nhiên, việc sử dụng new Array() lại khá ít dùng vì nó chậm và có một trường hợp khó hiểu.
Câu lệnh new Array(number) với number là một số, không khởi tạo mảng có 1 phần tử là number mà khởi tạo mảng có number phần tử.
💡 Để tránh nhầm lẫn, bạn chỉ nên sử dụng dấu ngoặc vuông [] để khởi tạo mảng (trừ khi bạn có mục đích đặc biệt nào khác).
Mảng nhiều chiều
Mảng trong JavaScript có thể chứa phần tử cũng là một mảng. Đó gọi là mảng nhiều chiều.
Ví dụ sử dụng mảng hai chiều để lưu ma trận 2×2:
Phương thức toString()
Array có triển khai phương thức toString() theo cách riêng. Phương thức này trả về một string chứa giá trị của các phần tử mảng – được ngăn cách nhau bởi dấu phẩy:
Ví dụ cộng array với số:
Bởi vì, array không có phương thức Symbol.toPrimitive và valueOf() mà chỉ có phương thức toString().
Vì vậy khi thực hiện phép cộng trên, [] trở thành string rỗng, [1] trở thành “1” và [1,2] trở thành “1,2”. Nên đoạn code trên tương đương với:
Tiếp theo, khi cộng string với số thì số sẽ được chuyển đổi kiểu dữ liệu về string. Nên kết quả thu được như trên.
So sánh array trong JavaScript
Tương tự như object, array cũng là kiểu dữ liệu tham chiếu. Vì vậy, việc so sánh array là so sánh qua tham chiếu.
Nghĩa là hai array chỉ bằng nhau khi chúng cùng tham chiếu. Ngược lại, dù cho hai array có các phần tử giống nhau thì chúng cũng không bằng nhau.
Để so sánh hai array với nhau theo giá trị các phần tử, bạn có thể tham khảo cách mình triển khai với object trong bài viết: So sánh hai object trong JavaScript.
Tổng kết
Array trong JavaScript là một loại object đặc biệt dùng để lưu trữ dữ liệu theo thứ tự.
Để khởi tạo array, bạn có hai cách:
Cách gọi new Array(number) với number là số sẽ tạo một mảng mới có giá trị length là number, nhưng lại không có phần tử nào.
Thuộc tính length có giá trị là độ dài của mảng, chính xác hơn thì length bằng giá trị chỉ số lớn nhất cộng thêm 1 đơn vị. Mỗi khi bạn thêm/xóa phần tử trong mảng thì thuộc tính length tăng/giảm tương ứng.
Nhưng bạn cũng có thể thay đổi trực tiếp giá trị của length. Nếu giá trị của length giảm đi thì mảng cũng bị cắt ngắn đi. Và khi length bằng 0, đồng nghĩa với mảng bị xóa.
Một số phương thức phổ biến trong mảng là:
- arr.push(item1, item2,…): thêm một hoặc nhiều phần tử vào cuối mảng.
- arr.pop(): lấy ra và trả về phần tử cuối cùng của mảng.
- arr.shift(): lấy ra và trả về phần tử đầu tiên của mảng.
- arr.unshift(item1, item2,…): thêm một hay nhiều phần tử vào đầu mảng.
Có ba cách để duyệt hết tất cả các phần tử của mảng:
- Vòng lặp for với chỉ số for (let i=0; i < arr.length; i++): cách này chạy nhanh nhất.
- Vòng lặp for (let item of arr): cách này ngắn gọn, nên dùng khi không quan tâm chỉ số.
- Vòng lặp for (let i in arr): cách này không tối ưu cho array, không nên dùng.
So sánh array thực chất là so sánh theo tham chiếu. Để so sánh từng phần tử của mảng, bạn có thể dùng vòng lặp for…of để duyệt hết tất cả các phần tử hoặc sử dụng thư viện _.isEqual.
Thực hành
Bài 1
Đoạn code sau hiển thị như thế nào:
Bài 2
Hãy viết code thực hiện các bước sau:
- Tạo mảng letters với hai phần tử “a” và “b”.
- Thêm phần tử “c” vào cuối mảng.
- Thay đổi giá trị của phần tử ở giữa thành “d”.
- Lấy ra và trả về giá trị phần tử đầu tiên của mảng.
- Thêm hai số 1, 2 vào đầu mảng.
Bài 3
Kết quả hiển thị là gì?
Bài 4
Viết hàm sumInput thực hiện các yêu cầu sau:
- Sử dụng hàm prompt để yêu cầu người dùng nhập vào các số và lưu vào một mảng.
- Dừng hỏi người dùng khi giá trị nhập vào không phải là số bình thường.
- Tính và in ra tổng các số người dùng nhập.
Tham khảo:
- MDN Arrays
- Arrays