Giả sử bạn đang tham gia một dự án phát triển web phức tạp. Nhiệm vụ của bạn là xử lý, lọc và phân tích dữ liệu được thu thập từ nhiều API khác nhau một cách hiệu quả. Đây là lúc mà việc thành thạo các Array Functions (phương thức mảng) nâng cao trong JavaScript phát huy tác dụng. Các hàm này không chỉ giúp bạn viết ít code hơn mà còn nâng cao hiệu suất và củng cố kỹ năng phát triển của bạn.

Hãy cùng VietnamWorks inTECH khám phá 10 phương thức mảng hàng đầu mà mọi Senior Developer nên biết để giải quyết các nhiệm vụ phức tạp một cách nhanh chóng và chính xác.

I. 10 phương thức mảng thiết yếu

1. forEach()

Đây là một phương thức JavaScript được sử dụng để đi qua từng phần tử trong một mảng và thực hiện một hành động cụ thể cho mỗi phần tử đó. Nó là một phương thức rất hữu ích để xử lý, lọc và biến đổi dữ liệu trong mảng.

Ví dụ: 

let numbers = [1, 2, 3, 4, 5];

numbers.forEach(function(number) {

  console.log(number);

});

Output

1

2

3

4

5

Trong ví dụ trên, hàm forEach() đi qua từng phần tử của mảng numbers và in ra từng giá trị.

Lưu ý:

  • forEach() không trả về giá trị (undefined), vì vậy không thể sử dụng return để thoát khỏi vòng lặp sớm.

  • forEach() không làm thay đổi mảng gốc, nhưng có thể thay đổi giá trị của các phần tử trong mảng nếu chúng là các đối tượng.

  • forEach() không thể sử dụng với các cấu trúc dữ liệu không phải là mảng (như đối tượng), trừ khi đối tượng đó có thuộc tính giống như mảng.

 2. map()

Hàm map() trong JavaScript là một phương thức được sử dụng để chuyển đổi từng phần tử trong một mảng thành một phần tử mới trong một mảng khác bằng cách gọi một hàm callback lên từng phần tử của mảng gốc. Khác với forEach(), map() trả về một mảng mới với các giá trị đã được chuyển đổi.

Ví dụ:

let numbers = [1, 2, 3, 4, 5];

let doubled = numbers.map(function(number) {

  return number * 2;

});

 

console.log(doubled);

Output

[2, 4, 6, 8, 10]

Trong ví dụ trên, hàm map() truy cập từng phần tử của mảng numbers, nhân mỗi phần tử với 2 và tạo ra một mảng mới doubled chứa các giá trị đã được nhân đôi.

Lưu ý:

  • map() không làm thay đổi mảng gốc mà tạo ra một mảng mới.

  • Hàm callback được truyền vào map() phải trả về một giá trị mới cho mỗi phần tử, nếu không các phần tử trong mảng mới sẽ là undefined.

  • map() cũng có thể được sử dụng với các đối tượng mảng-like (như NodeList) bằng cách chuyển đổi chúng thành mảng trước khi sử dụng.

3. filter()

Đây là một phương thức được sử dụng để lọc các phần tử trong một mảng dựa trên một điều kiện cụ thể. Nó hoạt động bằng cách duyệt qua từng phần tử trong mảng và kiểm tra xem phần tử đó có thỏa mãn điều kiện hay không. Nếu phần tử thỏa mãn điều kiện, nó sẽ được giữ lại trong mảng mới. Nếu không, nó sẽ bị loại bỏ.

Ví dụ: Lấy số chẵn từ một mảng:

const numbers = [1, 2, 3, 4, 5];

const evenNumbers = numbers.filter(number => number % 2 === 0);
console.log(evenNumbers);

// Output [2, 4]

Lưu ý:

  • filter() không làm thay đổi mảng gốc mà tạo ra một mảng mới.

  • Hàm callback được truyền vào filter() phải trả về một giá trị boolean để quyết định liệu phần tử có nên được giữ lại trong mảng mới hay không.

  • filter() có thể được sử dụng với các đối tượng mảng-like (như NodeList) bằng cách chuyển đổi chúng thành mảng trước khi sử dụng.

4. reduce()

Hàm reduce() trong JavaScript được sử dụng để áp dụng một hàm lên mỗi phần tử của mảng (từ trái sang phải) để kết hợp chúng thành một giá trị duy nhất.

Phương thức này khá linh hoạt, nó có khả năng tính tổng và tính trung bình, tìm giá trị lớn nhất và nhỏ nhất, thậm chí tạo ra các cấu trúc dữ liệu phức tạp.

Ví dụ: Tìm tổng của một mảng

const numbers = [1, 2, 3, 4];

const sum = numbers.reduce((accumulator, current) => accumulator + current, 0);
console.log(sum);

// Output: 10

5. find()

Trong JavaScript hàm find() được sử dụng để tìm và trả về giá trị của phần tử đầu tiên trong mảng thỏa mãn một điều kiện nào đó được cung cấp bởi hàm callback. Nếu không có phần tử nào thỏa mãn điều kiện, find() sẽ trả về undefined. Phương thức này rất hữu ích cho việc tra cứu nhanh và loại bỏ toàn bộ vòng lặp của mảng.

Ví dụ: Tìm phần tử đầu tiên lớn hơn 3

const numbers = [1, 2, 4, 5];

const firstGreaterThanThree = numbers.find(number => number > 3);
console.log(firstGreaterThanThree);

// Output: 4

Lưu ý: find() chỉ trả về phần tử đầu tiên thỏa mãn điều kiện. Nếu cần tìm tất cả các phần tử thỏa mãn điều kiện, bạn nên sử dụng filter().

6. findIndex()

Đây là một phương thức được sử dụng để tìm kiếm vị trí của phần tử đầu tiên trong một mảng thỏa mãn một điều kiện cụ thể. Nó hoạt động tương tự như hàm find(), nhưng thay vì trả về chính phần tử tìm thấy, nó trả về vị trí (index) của phần tử đó trong mảng.

Ví dụ: Tìm chỉ số của phần tử đầu tiên lớn hơn 3

const numbers = [1, 2, 4, 5];

const indexOfFirstGreaterThanThree = numbers.findIndex(number => number > 3);
console.log(indexOfFirstGreaterThanThree);

// Output: 2

7. some()

Hàm some() trong JavaScript được sử dụng để kiểm tra xem có ít nhất một phần tử trong mảng thỏa mãn một điều kiện nào đó được cung cấp bởi hàm callback hay không. Hàm some() trả về true nếu có ít nhất một phần tử thỏa mãn điều kiện và false nếu không có phần tử nào thỏa mãn.

Ví dụ: Kiểm tra xem có phần tử nào trong mảng lớn hơn 10 không

const numbers = [1, 5, 8, 12];

const hasElementGreaterThanTen = numbers.some(number => number > 10);
console.log(hasElementGreaterThanTen);

// Output: true

Lưu ý:

  • some() dừng lại ngay sau khi tìm thấy phần tử thỏa mãn điều kiện và không kiểm tra các phần tử phía sau nữa.

  • some() không làm thay đổi mảng gốc.

8. every()

Hàm này được sử dụng để kiểm tra xem tất cả các phần tử trong mảng có thỏa mãn một điều kiện nào đó được cung cấp bởi hàm callback hay không. Hàm every() trả về true nếu tất cả các phần tử trong mảng đều thỏa mãn điều kiện và false nếu có ít nhất một phần tử không thỏa mãn.

Phương thức này hữu ích cho việc xác thực dữ liệu, kiểm tra mọi phần tử theo cấu trúc đã chỉ định và thực hiện kiểm tra chất lượng.

Ví dụ: Kiểm tra xem tất cả các phần tử trong một mảng có phải là chuỗi hay không

const data = ["apple", "banana", 10];

const allStrings = data.every(element => typeof element === "string");
console.log(allStrings);

// Output: false

9. includes()

Trong JavaScript hàm includes() được sử dụng để kiểm tra xem một mảng có chứa một giá trị cụ thể hay không. Hàm includes() trả về true nếu mảng chứa giá trị đó và false nếu không. Điều này rất quan trọng trong việc xác định các điểm dữ liệu riêng lẻ hoặc tạo logic có điều kiện dựa trên thành viên mảng.

Ví dụ: Kiểm tra xem mảng có chứa giá trị “orange” hay không

const fruits = ["apple", "banana", "cherry"];

const hasOrange = fruits.includes("orange");
console.log(hasOrange);

// Output: false

10. flat()

Hàm này được sử dụng để "làm phẳng" một mảng nhiều chiều thành một mảng một chiều. Điều này có nghĩa là các mảng lồng nhau trong mảng ban đầu sẽ được giải nén để tạo thành một mảng duy nhất chứa tất cả các phần tử.

Phương thức này rất hữu ích trong việc đơn giản hóa các mảng lồng nhau, làm việc với dữ liệu từ các API có cấu trúc lồng nhau, và lưu trữ dữ liệu để tiếp tục xử lý.

Ví dụ: Làm phẳng một mảng lồng nhau

const nestedArray = [1, [2, 3], 4];

const flattenedArray = nestedArray.flat();
console.log(flattenedArray);

// Output: [1, 2, 3, 4]

Lưu ý:

  • flat() không làm thay đổi mảng gốc mà trả về một mảng mới đã làm phẳng.

  • flat() không làm phẳng các giá trị null và undefined.

  • Nếu bạn cần làm phẳng một mảng mà không biết độ sâu của mảng, bạn có thể sử dụng flat(Infinity) để đảm bảo làm phẳng toàn bộ mảng.

  • flat() là một phương thức mới được thêm vào trong Javascript phiên bản ES2019, vì vậy hãy đảm bảo rằng phần mềm của bạn hỗ trợ nó.

II. Một số mẹo gia tăng năng suất làm việc

Bạn vừa tìm hiểu các kiến thức cơ bản, sau đây hãy cùng tìm hiểu một số thủ thuật giúp nâng cao tay nghề gõ code của bạn

1. Phương pháp nối mảng

Nhiều phương pháp của mảng có thể được xâu chuỗi lại với nhau để thực hiện các thay đổi phức tạp một cách rõ ràng và dễ hiểu.

Ví dụ, bạn có thể lọc các số chẵn từ một mảng và sau đó biến đổi chúng thành các số bình phương tương ứng trong cùng một dòng:

const numbers = [1, 2, 3, 4, 5];

const evenSquares = numbers.filter(number => number % 2 === 0)
.map(number => number * number);

console.log(evenSquares);

// Output: [4, 16]

2. Các hàm callback tùy chỉnh

Hãy nhớ rằng nhiều hàm mảng phụ thuộc vào hàm callback.

Để cải thiện chất lượng code, hãy xây dựng các hàm callback mạnh mẽ và được định nghĩa rõ ràng. Điều này giúp xử lý các tình huống đặc biệt, đảm bảo tính an toàn kiểu dữ liệu (bằng cách ghi rõ kiểu dữ liệu mong muốn) và tăng khả năng bảo trì code.

Ví dụ, một hàm callback được định nghĩa rõ để kiểm tra xem một số có chẵn hay không có thể trông như thế này:

function isEven(number) {
if (typeof number !== 'number') {
throw new TypeError('Input must be a number');
}
return number % 2 === 0;
}

3. Xử lý lỗi

Dữ liệu bất ngờ hoặc các đoạn thiếu có thể dẫn đến lỗi. Để xử lý các trường hợp này một cách dễ dàng, bạn có thể sử dụng một thành phần try-catch:

const numbers = [1, "two", 3];

try {
const doubledNumbers = numbers.map(number => number * 2);
console.log(doubledNumbers);

// [2, NaN, 6] (Error for "two")

} catch (error) {
console

4. Cân nhắc về hiệu suất

Không phải tất cả các phương thức mảng đều có hiệu suất giống nhau. Trong đoạn này, chúng ta sẽ thảo luận ngắn gọn về tác động của chúng đến hiệu năng (ví dụ, forEach so với vòng lặp for) khi xử lý các mảng lớn hoặc phức tạp.

Các yếu tố ảnh hưởng:

  • Bộ nhớ (Memory): Lượng dữ liệu lớn có thể khiến hệ thống quá tải. Điều này có thể ảnh hưởng đến hiệu suất của bất kỳ phương thức mảng nào, vì chúng cần lưu trữ và xử lý dữ liệu trong bộ nhớ.

  • Vòng lặp (Loops): Truy cập vào từng phần tử của một mảng lớn trong một vòng lặp for sẽ tốn thời gian. Số lần lặp càng nhiều thì thời gian xử lý càng lâu.

  • Phần tử phức tạp (Complex elements): Xử lý dữ liệu phức tạp bên trong các phần tử của mảng (ví dụ, các đối tượng hoặc mảng lồng nhau) thường chậm hơn đáng kể so với xử lý các giá trị đơn giản (số, chuỗi).

  • forEach vs. Vòng lặp for: Về mặt hiệu suất, forEach thường tương đương với vòng lặp for. Tuy nhiên, forEach cung cấp khả năng kiểm soát nhiều hơn và dễ đọc hơn so với vòng lặp for.

Một số mẹo nhỏ giúp bạn tối ưu hóa về hiệu suất:

  • Sử dụng cấu trúc dữ liệu thay thế cho tra cứu thông thường: Trong một số trường hợp, sử dụng các cấu trúc dữ liệu được thiết kế riêng cho việc tra cứu nhanh chóng, chẳng hạn như Map hoặc Set, có thể hiệu quả hơn so với các phương thức mảng thường thấy.

  • Chia nhỏ các hoạt động lớn: Nếu bạn đang thực hiện một loạt các thao tác trên một mảng lớn, hãy cân nhắc chia nhỏ chúng thành các bước nhỏ hơn. Điều này có thể giúp cải thiện hiệu năng và dễ quản lý hơn.

  • Kiểm tra code để tìm vấn đề (tối ưu hóa sau!): Trước khi vội vàng áp dụng các kỹ thuật tối ưu hóa phức tạp, hãy dành thời gian kiểm tra code của bạn để xác định các điểm gây ra chậm trễ. Đôi khi, những thay đổi đơn giản trong logic hoặc thuật toán có thể mang lại hiệu quả đáng kể.

  • Sử dụng vòng lặp truyền thống cho các tập dữ liệu thực sự lớn: Đối với các tập dữ liệu cực kỳ lớn, đặc biệt là trong các trình duyệt cũ hơn có thể không có triển khai tối ưu cho các phương thức mảng, việc sử dụng vòng lặp for truyền thống đôi khi có thể mang lại hiệu quả tốt hơn. Tuy nhiên, hãy cân nhắc kỹ lưỡng giữa hiệu năng và tính dễ đọc của code.

5. Các phương pháp tốt nhất

  • Kết hợp các Hàm: Như đã đề cập trước đó, việc nối chuỗi nhiều tác vụ giúp thực hiện các hoạt động nhanh chóng và mạnh mẽ. Đừng ngại thử nghiệm và kết hợp chúng để tạo ra những thay đổi phức tạp chỉ trong một dòng.

  • Bất Biến (Immutability): Bất cứ khi nào có thể, hãy cố gắng tạo các mảng mới thay vì thay đổi các mảng cũ. Điều này giúp cải thiện khả năng đọc code và giảm thiểu nguy cơ xảy ra các tác động không mong muốn. Sử dụng các phương thức như map, filter và slice để tạo mảng mới.

  • Xử lý Lỗi: Luôn sử dụng xử lý lỗi hoạt động trong các hàm callback của bạn để bắt các inputs lạ hoặc các phần tử bị thiếu. Điều này giúp tránh lỗi do việc kết hợp các phương thức mảng và gây ra sự cố cho chương trình của bạn.

Lời kết

Việc thành thạo các hàm mảng trong JavaScript không chỉ giúp bạn làm việc hiệu quả với dữ liệu mà còn là một kỹ năng quan trọng để tiến đến vị trí Senior Developer. Hãy thực hành và áp dụng những kiến thức này vào dự án để phát triển kỹ năng và nâng cao trình độ lập trình của mình. Nếu thấy bài viết hữu ích, đừng quên chia sẻ cho bạn bè cùng biết nhé!

VietnamWorks inTECH

TẠO TÀI KHOẢN MỚI: XEM FULL “1 TÁCH CODEFEE” - NHẬN SLOT TƯ VẤN CV TỪ CHUYÊN GIA - CƠ HỘI RINH VỀ VOUCHER 200K