forEach JavaScript là gì? So sánh, ví dụ và ứng dụng thực tế

Lập trình với JavaScript không chỉ là viết ra những dòng lệnh hoạt động, mà còn là lựa chọn đúng công cụ để mã nguồn trở nên rõ ràng và hiệu quả hơn. Trong quá trình xử lý mảng, câu hỏi forEach JavaScript là gì thường xuất hiện như một cách mở đầu cho việc tìm hiểu các phương pháp thao tác dữ liệu trực quan hơn. Cùng khám phá qua bài viết sau nhé.

forEach JavaScript là gì

forEach JavaScript là gì?

forEach() là một phương thức có sẵn trong đối tượng mảng (Array) của JavaScript, dùng để lặp qua từng phần tử trong mảng và thực thi một hàm callback cho mỗi phần tử đó.

Đây là một cách viết ngắn gọn và rõ ràng thay thế cho vòng lặp for truyền thống, đặc biệt khi bạn chỉ muốn thực hiện một hành động nào đó trên từng phần tử mà không cần tạo ra giá trị mới hay trả về kết quả.

Phương thức này không thay đổi mảng gốc và không trả về giá trị (luôn trả về undefined). forEach() thường được sử dụng trong các tác vụ như hiển thị danh sách, ghi log, thao tác DOM hoặc thực thi logic đơn giản cho từng phần tử trong mảng.

Cú pháp và cách sử dụng cơ bản của forEach JavaScript

Phương thức forEach() trong JavaScript được sử dụng để lặp qua từng phần tử của mảng và thực thi một hàm callback với mỗi phần tử đó. Đây là cách thức lặp phổ biến nhờ cú pháp ngắn gọn, dễ đọc và phù hợp với lập trình hàm (functional programming).

Cú pháp chuẩn: array.forEach(callback, thisArg)

Phương thức forEach() có cú pháp như sau:

javascript

array.forEach(function callback(currentValue, index, array) {

  // thao tác với phần tử

}, thisArg);

Trong đó:

array là mảng bạn muốn duyệt qua.

callback là hàm sẽ được thực thi cho mỗi phần tử trong mảng.

thisArg (tùy chọn) là giá trị được sử dụng làm this khi thực thi callback.

Giải thích các tham số

currentValue: Phần tử hiện tại đang được xử lý trong mảng.

index: Chỉ số (vị trí) của phần tử hiện tại trong mảng.

array: Chính mảng đang được gọi forEach() trên đó.

thisArg (tuỳ chọn): Một giá trị sẽ được sử dụng làm this trong quá trình thực thi hàm callback, thường được dùng khi cần tham chiếu đến đối tượng bên ngoài.

Lưu ý: Tất cả các tham số trừ thisArg đều được tự động truyền vào callback theo thứ tự.

Ví dụ cơ bản: lặp mảng số, mảng chuỗi

Dưới đây là ví dụ đơn giản sử dụng forEach() để in ra từng phần tử trong mảng:

javascript

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

numbers.forEach(function(number, index) {

  console.log(`Phần tử thứ ${index}: ${number}`);

});

Kết quả:

less

Phần tử thứ 0: 1

Phần tử thứ 1: 2

Phần tử thứ 2: 3

Phần tử thứ 3: 4

Phần tử thứ 4: 5

Hoặc với mảng chuỗi:

javascript

const fruits = [“Táo”, “Chuối”, “Cam”];

fruits.forEach((fruit) => {

  console.log(`Tôi thích ăn ${fruit}`);

});

Kết quả:

css

Tôi thích ăn Táo 

Tôi thích ăn Chuối 

Tôi thích ăn Cam

Ví dụ nâng cao khi sử dụng forEach JavaScript

Sau khi đã nắm được cách sử dụng cơ bản, bạn có thể khai thác forEach() một cách linh hoạt hơn trong những tình huống nâng cao. Dưới đây là các ví dụ thực tế giúp bạn hiểu rõ cách vận dụng forEach() trong nhiều ngữ cảnh khác nhau.

Sử dụng arrow function với forEach()

Thay vì dùng function truyền thống, bạn có thể viết ngắn gọn hơn với arrow function:

javascript

const names = [“An”, “Bình”, “Chi”];

names.forEach((name, index) => {

  console.log(`${index + 1}. ${name}`);

});

Kết quả:

markdown

1. An 

2. Bình 

3. Chi

➡️ Việc sử dụng arrow function giúp mã ngắn gọn hơn và dễ đọc, đặc biệt khi logic xử lý đơn giản.

Truyền thisArg để tùy biến ngữ cảnh

Bạn có thể truyền một đối tượng làm thisArg để sử dụng trong hàm callback:

javascript

const counter = {

  prefix: “Item”,

};

const items = [10, 20, 30];

items.forEach(function (value, index) {

  console.log(`${this.prefix} ${index + 1}: ${value}`);

}, counter);

Kết quả:

yaml

Item 1: 10 

Item 2: 20 

Item 3: 30

➡️ Đây là cách hiệu quả khi bạn muốn tái sử dụng một đối tượng hoặc tham chiếu tới this bên ngoài trong callback.

Lặp qua mảng object

forEach() rất tiện lợi khi thao tác với mảng các object:

javascript

const users = [

  { name: “Mai”, age: 25 },

  { name: “Hùng”, age: 30 },

  { name: “Linh”, age: 22 },

];

users.forEach((user) => {

  console.log(`${user.name} năm nay ${user.age} tuổi.`);

});

Kết quả:

css

Mai năm nay 25 tuổi. 

Hùng năm nay 30 tuổi. 

Linh năm nay 22 tuổi.

➡️ Đây là một trong những cách phổ biến nhất để hiển thị dữ liệu trong ứng dụng thực tế.

forEach() với mảng lồng nhau

Khi mảng chứa các mảng con, bạn có thể lồng nhiều vòng forEach() để duyệt:

javascript

const matrix = [

  [1, 2],

  [3, 4],

  [5, 6],

];

matrix.forEach((row, rowIndex) => {

  row.forEach((value, colIndex) => {

    console.log(`Phần tử tại [${rowIndex}][${colIndex}] = ${value}`);

  });

});

Kết quả:

Phần tử tại [0][0] = 1 

Phần tử tại [0][1] = 2 

Phần tử tại [1][0] = 3 

Phần tử tại [1][1] = 4 

Phần tử tại [2][0] = 5 

Phần tử tại [2][1] = 6

➡️ Cách làm này rất phù hợp khi làm việc với ma trận, bảng dữ liệu hoặc dữ liệu tổ chức dạng phân cấp.

Ứng dụng thực tế trong thao tác DOM, dữ liệu JSON

Phương thức forEach() thường xuyên được sử dụng trong các tác vụ tương tác với giao diện người dùng (DOM) hoặc xử lý dữ liệu từ API trả về dạng JSON. Dưới đây là hai ví dụ tiêu biểu:

✔️ Ví dụ 1: Thêm danh sách mục vào giao diện HTML

html

<ul id=”fruits-list”></ul>

javascript

const fruits = [“Táo”, “Chuối”, “Dưa hấu”];

const list = document.getElementById(“fruits-list”);

fruits.forEach((fruit) => {

  const li = document.createElement(“li”);

  li.textContent = fruit;

  list.appendChild(li);

});

➡️ Mỗi phần tử trong mảng sẽ được chuyển thành một thẻ <li> và hiển thị lên trình duyệt.

✔️ Ví dụ 2: Duyệt qua dữ liệu JSON từ API

Giả sử bạn nhận được dữ liệu người dùng từ API như sau:

javascript

const response = [

  { id: 1, name: “Lan” },

  { id: 2, name: “Minh” },

  { id: 3, name: “Phúc” }

];

response.forEach((user) => {

  console.log(`ID: ${user.id}, Tên: ${user.name}`);

});

➡️ forEach() giúp bạn xử lý từng object trong mảng một cách trực quan, thuận tiện để hiển thị, lọc hoặc thao tác sâu hơn trong ứng dụng web.

Xem thêm: Tìm việc Java tại Careerlink.vn

Ưu điểm và nhược điểm của forEach JavaScript

Phương thức forEach() ngày càng trở nên phổ biến trong lập trình JavaScript hiện đại, đặc biệt là trong các ứng dụng web. Với cú pháp ngắn gọn và khả năng diễn đạt rõ ràng ý đồ lập trình, forEach() giúp lập trình viên dễ dàng thao tác với dữ liệu và xử lý logic từng phần tử của mảng mà không cần đến các vòng lặp phức tạp.

Tuy nhiên, giống như bất kỳ công cụ nào khác, forEach() cũng có những điểm mạnh nổi bật và mặt hạn chế cần lưu ý khi sử dụng.

Ưu điểm forEach JavaScript

Cú pháp đơn giản, dễ học, dễ viết:
So với vòng lặp for truyền thống, forEach() giúp rút gọn đáng kể số dòng mã và tránh những lỗi liên quan đến biến đếm hoặc điều kiện dừng không chính xác.

Tăng tính rõ ràng, dễ đọc:
forEach() giúp người đọc dễ dàng hiểu rằng đoạn mã đang thực hiện một hành động cho từng phần tử của mảng. Đây là một cách thể hiện ý định lập trình rõ ràng, đặc biệt hữu ích trong môi trường làm việc nhóm.

Tránh lỗi ngoài chỉ số mảng:
Vì không cần xử lý chỉ số một cách thủ công như for (let i = 0; i < arr.length; i++), nên nguy cơ vượt chỉ số mảng hoặc sai logic điều kiện giảm đi đáng kể.

Nhược điểm forEach JavaScript

Không thể sử dụng break, continue hay return để thoát sớm:
Khác với vòng lặp for hay for…of, bạn không thể thoát khỏi vòng lặp forEach() một cách chủ động khi đạt điều kiện nào đó. Điều này gây bất tiện trong một số trường hợp cần dừng sớm.

Không trả về giá trị (luôn trả về undefined):
forEach() chỉ dùng để thực thi hành động trên từng phần tử chứ không tạo ra mảng mới. Vì vậy, bạn không thể sử dụng nó để “biến đổi” dữ liệu giống như map().

Không hoạt động trực tiếp với async/await:
Nếu bạn sử dụng await trong callback của forEach(), hàm sẽ không đợi từng bước hoàn thành mà tiếp tục chạy tuần tự. Điều này khiến việc xử lý bất đồng bộ trở nên khó kiểm soát nếu không dùng các giải pháp thay thế như for…of kết hợp await.

So sánh forEach JavaScript với các phương thức lặp khác

JavaScript cung cấp nhiều cách để lặp qua các phần tử trong mảng, mỗi cách có ưu và nhược điểm riêng. Việc hiểu rõ sự khác biệt giữa forEach() và các phương thức khác sẽ giúp bạn chọn được giải pháp phù hợp nhất với mục đích sử dụng.

for và for…of vs forEach()

for là vòng lặp truyền thống, cho phép bạn kiểm soát hoàn toàn chỉ số, điều kiện dừng, và sử dụng break hoặc continue.

for…of đơn giản hơn, phù hợp để duyệt mảng theo thứ tự phần tử nhưng không có chỉ số (index) như forEach().

forEach() giúp mã ngắn gọn, dễ đọc hơn nhưng không thể dừng vòng lặp sớm.

Ví dụ so sánh:

javascript

// for

for (let i = 0; i < arr.length; i++) {

  if (arr[i] === 3) break;

}

// forEach (không thể break)

arr.forEach((num) => {

  if (num === 3) return; // chỉ thoát khỏi callback, không dừng vòng lặp

});

➡️ Dùng for hoặc for…of khi cần dừng vòng lặp giữa chừng.

map() vs forEach()

map() tạo ra một mảng mới từ kết quả của callback, dùng khi bạn muốn biến đổi dữ liệu.

forEach() chỉ thực thi logic, không trả về mảng mới.

Ví dụ:

javascript

const numbers = [1, 2, 3];

// map

const doubled = numbers.map(num => num * 2); // [2, 4, 6]

// forEach

const result = [];

numbers.forEach(num => result.push(num * 2)); // [2, 4, 6]

➡️ Nếu mục đích là xử lý và trả về mảng mới → dùng map(). Nếu chỉ cần thao tác phụ → dùng forEach().

filter() và reduce() vs forEach()

filter() dùng để lọc phần tử thỏa mãn điều kiện, trả về mảng mới.

reduce() dùng để tính toán tích lũy như tổng, trung bình, nối chuỗi…

forEach() không trả về giá trị, không phù hợp cho lọc hoặc tích lũy.

Ví dụ:

javascript

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

// filter

const even = nums.filter(n => n % 2 === 0); // [2, 4]

// reduce

const total = nums.reduce((sum, n) => sum + n, 0); // 15

// forEach không trả về gì

let sum = 0;

nums.forEach(n => sum += n); // sum = 15

➡️ Sử dụng filter() hoặc reduce() khi bạn cần kết quả trả về, thay vì chỉ thực hiện hành động.

Gợi ý khi nào nên dùng forEach()

Bạn nên chọn forEach() khi:

Muốn thực hiện hành động phụ trên từng phần tử (hiển thị, ghi log, thay đổi DOM…).

Không cần dừng vòng lặp giữa chừng.

Không cần trả về giá trị từ callback.

Ưu tiên sự rõ ràng, dễ đọc trong code – đặc biệt với các mảng có kích thước nhỏ hoặc vừa.

Trong khi đó, với các thao tác phức tạp hơn như tạo mảng mới, lọc điều kiện, hoặc xử lý bất đồng bộ, bạn nên cân nhắc sử dụng các phương thức khác như map(), filter(), reduce(), hoặc for…of.

Các lỗi thường gặp khi sử dụng forEach JavaScript

Dù là một công cụ hữu ích và dễ sử dụng, forEach() trong JavaScript vẫn tồn tại một số điểm dễ gây hiểu nhầm hoặc lỗi logic cho người mới bắt đầu. Dưới đây là những lưu ý quan trọng và lỗi phổ biến mà bạn cần tránh khi làm việc với phương thức này.

Dùng forEach() với async/await

Một lỗi rất thường gặp là sử dụng async/await bên trong forEach() với kỳ vọng rằng nó sẽ đợi hoàn tất từng thao tác bất đồng bộ:

javascript

const tasks = [1, 2, 3];

tasks.forEach(async (task) => {

  await doSomething(task); // Không hoạt động như mong đợi

});

➡️ Sai lầm: forEach() không chờ các Promise hoàn thành. Vòng lặp vẫn tiếp tục mà không quan tâm đến await.

✅ Cách khắc phục: Dùng for…of thay thế khi cần xử lý bất đồng bộ có tuần tự:

javascript

for (const task of tasks) {

  await doSomething(task); // Đảm bảo chạy tuần tự

}

Nhầm lẫn giữa map() và forEach()

Một lỗi phổ biến khác là dùng forEach() khi thực ra cần sử dụng map():

javascript

const numbers = [1, 2, 3];

const doubled = numbers.forEach(num => num * 2); // doubled === undefined

➡️ Lý do: forEach() không trả về giá trị → không thể gán kết quả vào biến như map().

✅ Giải pháp: Dùng map() khi cần xử lý từng phần tử và thu được kết quả:

javascript

const doubled = numbers.map(num => num * 2); // [2, 4, 6]

Duyệt mảng rỗng hoặc mảng lồng nhau sai cách

forEach() không chạy callback nếu mảng rỗng. Người mới dễ nghĩ rằng hàm không hoạt động.

Khi làm việc với mảng lồng nhau, không xử lý đúng sẽ dẫn đến lỗi logic hoặc không duyệt đủ phần tử.

Ví dụ sai:

javascript

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

nested.forEach((row) => {

  console.log(row); // Chỉ in ra mảng con, không in từng giá trị

});

✅ Giải pháp: Dùng forEach() lồng nhau để duyệt chính xác:

javascript

nested.forEach((row) => {

  row.forEach((val) => console.log(val)); // 1 2 3 4

});

Không nhận ra callback không có giá trị trả về

Vì forEach() không trả về bất kỳ giá trị nào từ callback, người dùng dễ bị nhầm lẫn rằng mình có thể dùng return như trong map() hoặc filter().

javascript

const result = [1, 2, 3].forEach(num => {

  return num * 2;

});

console.log(result); // undefined

➡️ Đoạn mã trên không tạo ra mảng mới, result chỉ là undefined.

✅ Hãy nhớ rằng: forEach() phù hợp cho thực hiện hành động phụ, không dùng để xử lý và thu kết quả.

Các câu hỏi thường gặp về forEach JavaScript

Dù được đánh giá là dễ sử dụng, nhưng trong quá trình làm việc thực tế, forEach() vẫn thường đặt ra một số câu hỏi phổ biến cho cả người mới học lẫn lập trình viên có kinh nghiệm. Dưới đây là hai câu hỏi nổi bật cần làm rõ.

Dùng forEach() lồng nhau có được không?

Câu trả lời là có. forEach() có thể được sử dụng lồng nhau để duyệt qua các mảng hai chiều hoặc dữ liệu dạng lồng nhau (mảng chứa mảng). Tuy nhiên, khi triển khai, bạn cần xác định rõ cấp độ dữ liệu và đảm bảo rằng logic xử lý trong từng vòng lặp là chính xác. Nếu dữ liệu có nhiều lớp lồng nhau, việc sử dụng đệ quy hoặc các phương pháp xử lý chuyên biệt sẽ hiệu quả và dễ quản lý hơn là lồng quá nhiều vòng forEach().

forEach() có ảnh hưởng đến hiệu năng không?

Về mặt hiệu suất, forEach() hoàn toàn đáp ứng tốt cho hầu hết các trường hợp sử dụng thông thường. Tuy nhiên, nếu làm việc với tập dữ liệu rất lớn hoặc cần tối ưu hóa đến từng mili giây, bạn có thể xem xét sử dụng các vòng lặp như for hoặc for…of, vốn có tốc độ xử lý nhanh hơn do không sử dụng callback function. Ngoài ra, nếu cần thao tác bất đồng bộ một cách tuần tự, forEach() không phải là lựa chọn lý tưởng, vì nó không tương thích trực tiếp với async/await.

Tóm lại, forEach() là công cụ hiệu quả khi thao tác với từng phần tử trong mảng mà không cần kết quả trả về. Nhờ cú pháp ngắn gọn và tính rõ ràng, nó thường được dùng trong các tình huống xử lý dữ liệu giao diện hoặc lặp tuần tự. Tuy vậy, việc sử dụng đúng ngữ cảnh là điều cần thiết, đặc biệt khi làm việc với bất đồng bộ hoặc yêu cầu thoát sớm khỏi vòng lặp. Câu hỏi forEach JavaScript là gì không chỉ dừng ở cú pháp, mà còn liên quan đến việc hiểu rõ giới hạn và biết khi nào nên dùng map, filter, reduce hay for…of thay thế. Khi được áp dụng đúng cách, forEach() góp phần đơn giản hóa mã nguồn và tăng tính rõ ràng trong lập trình JavaScript.

Trí Nhân

Về Tác Giả

CareerLink

Sao chép thành công