Câu lệnh for…in trong JavaScript được giải thích: Cú pháp, những bẫy thường gặp và các thực tiễn tốt nhất

目次

1. Giới thiệu|Câu lệnh for…in Có Thể Giải Quyết Những Vấn Đề Nào?

JavaScript là một trong những ngôn ngữ lập trình được sử dụng rộng rãi nhất trong phát triển web. Trong số nhiều tính năng của nó, xử lý vòng lặp là thiết yếu để xử lý dữ liệu lặp lại.

Đặc biệt, câu lệnh for…in rất hữu ích khi lặp qua các thuộc tính của một đối tượng.

Mục đích của Bài Viết Này

Bài viết này giải thích chi tiết các điểm sau:

  • Cú pháp cơ bản và cách sử dụng câu lệnh for…in của JavaScript
  • Những lưu ý quan trọng khi sử dụng nó với mảng
  • Sự khác biệt so với các cấu trúc vòng lặp khác như for…of và forEach
  • Các lỗi phổ biến và cách khắc phục

Những Gì Bạn Sẽ Học Được Từ Bài Viết Này

  • Cách xử lý hiệu quả các thuộc tính đối tượng và phần tử mảng
  • Các biện pháp phòng ngừa và mẫu sử dụng an toàn cho câu lệnh for…in
  • Các ví dụ mã thực tế và so sánh hiệu suất

Bài viết này được cấu trúc để giúp các lập trình viên JavaScript từ người mới bắt đầu đến trung cấp tiếp thu kiến thức thực tế có thể áp dụng trong các dự án thực tế.

Bây giờ, hãy cùng tìm hiểu kỹ hơn về cơ bản của câu lệnh for…in trong phần tiếp theo.

2. Câu lệnh for…in của JavaScript Là Gì? [Basic Explanation]

Trong JavaScript, câu lệnh for…in được sử dụng để lặp qua các thuộc tính của một đối tượng. Cú pháp này đặc biệt phù hợp với các đối tượng, cho phép bạn xử lý từng tên thuộc tính (khóa) một cách tuần tự.

Cú pháp Cơ Bản

Dưới đây là cú pháp cơ bản của câu lệnh for…in.

for (variable in object) {
  // 반복 처리
}

Mô tả Tham số:

  • biến : Lưu trữ tên thuộc tính hiện tại (khóa).
  • đối tượng : Đối tượng mà bạn muốn lặp qua.

Ví dụ: Liệt Kê Các Thuộc Tính Đối Tượng

const person = {
  name: "Taro",
  age: 25,
  city: "Tokyo"
};

for (const key in person) {
  console.log(`${key}: ${person[key]}`);
}

Đầu ra:

name: Taro
age: 25
city: Tokyo

Lưu Ý Quan Trọng: Thứ Tự Các Thuộc Tính Được Liệt Kê

Với câu lệnh for…in, thứ tự của các thuộc tính không được đảm bảo. Theo đặc tả JavaScript, khi các khóa là chuỗi, chúng không nhất thiết được xử lý theo thứ tự chúng được thêm vào. Nếu bạn cần thứ tự nghiêm ngặt, bạn nên sử dụng các cách tiếp cận khác như Object.keys().

Đặc Điểm Chính

  1. Truy cập dễ dàng vào các khóa đối tượng: Nó hữu ích khi bạn cần lấy động tên thuộc tính từ một đối tượng.
  2. Chỉ bao gồm các thuộc tính có thể liệt kê: Các thuộc tính không thể liệt kê ( enumerable: false ) sẽ bị loại trừ.
  3. Các thuộc tính kế thừa từ prototype cũng được liệt kê: Điều này có thể gây ra vấn đề, sẽ được giải thích chi tiết trong phần tiếp theo.

3. Mảng và Câu lệnh for…in|Những Điểm Quan Trọng Cần Lưu Ý

Câu lệnh for…in trong JavaScript được thiết kế để liệt kê các thuộc tính đối tượng, nhưng nó cũng có thể được sử dụng với mảng. Tuy nhiên, khi áp dụng cho mảng, có một số lưu ý quan trọng. Phần này giải thích hành vi của nó và các bẫy tiềm ẩn một cách chi tiết.

Hành Vi Cơ Bản Với Mảng

Hãy xem xét ví dụ sau.

const fruits = ["Apple", "Banana", "Orange"];

for (const index in fruits) {
  console.log(index, fruits[index]);
}

Đầu ra:

0 Apple  
1 Banana  
2 Orange

Lưu Ý 1: Các Thuộc Tính Prototype Có Thể Được Liệt Kê

Array.prototype.newMethod = function () {
  return "New method";
};

for (const index in fruits) {
  console.log(index, fruits[index]);
}

Đầu ra:

0 Apple  
1 Banana  
2 Orange  
newMethod undefined

Giải pháp:

for (const index in fruits) {
  if (fruits.hasOwnProperty(index)) {
    console.log(index, fruits[index]);
  }
}

Lưu Ý 2: Thứ Tự Không Được Đảm Bảo

const data = [];
data[10] = "Apple";
data[1] = "Banana";
data[5] = "Orange";

for (const index in data) {
  console.log(index, data[index]);
}

Đầu ra:

1 Banana  
5 Orange  
10 Apple

Cảnh báo 3: Các chỉ mục được coi là chuỗi

const numbers = [10, 20, 30];
for (const index in numbers) {
  console.log(typeof index); // "string"
}

Giải pháp:

for (const index in numbers) {
  const numIndex = parseInt(index, 10);
  console.log(numIndex, numbers[numIndex]);
}

Tóm tắt

  • Câu lệnh for…in phù hợp hơn cho các đối tượng hơn là mảng.
  • Khi thứ tự hoặc chỉ mục số học quan trọng, for…of hoặc vòng lặp for tiêu chuẩn được khuyến nghị.

4. Sự khác nhau giữa các câu lệnh for…in và for…of [With Comparison Table]

Trong JavaScript, cả câu lệnh for…infor…of đều được dùng để lặp, nhưng mục đích và hành vi của chúng khác nhau đáng kể.

So sánh cú pháp cơ bản

for…in:

const obj = { a: 1, b: 2, c: 3 };
for (const key in obj) {
  console.log(key); // Retrieves keys
}

for…of:

const arr = [10, 20, 30];
for (const value of arr) {
  console.log(value); // Retrieves values
}

Bảng so sánh

Itemfor…infor…of
TargetObjects and arraysArrays and iterable objects
OutputProperty names (keys)Actual values
Prototype enumerationMay be enumeratedNot enumerated
Order guaranteeNot guaranteedGuaranteed

Ví dụ thực tế|Sự khác nhau trong xử lý mảng

const arr = ['a', 'b', 'c'];

// for...in
for (const index in arr) {
  console.log(index); // Output: 0, 1, 2
}

// for...of
for (const value of arr) {
  console.log(value); // Output: 'a', 'b', 'c'
}

Tóm tắt

  • for…in: Phù hợp nhất để xử lý các khóa của đối tượng.
  • for…of: Lý tưởng cho mảng và các đối tượng có thể lặp.

5. Ví dụ thực tế: Sử dụng nâng cao và các thực hành tốt cho câu lệnh for…in

Phần này giới thiệu các ví dụ nâng cao sử dụng câu lệnh for…in của JavaScript, cùng với các thực hành tốt hữu ích trong phát triển thực tế.

1. Ví dụ 1|Lọc thuộc tính của đối tượng

const user = {
  name: "Tanaka",
  age: 30,
  email: "tanaka@example.com",
  password: "secret123"
};

const publicData = {};
for (const key in user) {
  if (key !== "password") {
    publicData[key] = user[key];
  }
}
console.log(publicData);

Kết quả:

{ name: 'Tanaka', age: 30, email: 'tanaka@example.com' }

2. Ví dụ 2|Xử lý các đối tượng lồng nhau

const data = {
  user: {
    name: "Sato",
    info: {
      age: 28,
      city: "Osaka"
    }
  }
};

function printNested(obj) {
  for (const key in obj) {
    if (typeof obj[key] === "object") {
      printNested(obj[key]);
    } else {
      console.log(`${key}: ${obj[key]}`);
    }
  }
}

printNested(data);

Kết quả:

name: Sato
age: 28
city: Osaka

3. Thực hành tốt|Loại trừ các thuộc tính prototype

const obj = { a: 1, b: 2 };
Object.prototype.c = 3;

for (const key in obj) {
  if (obj.hasOwnProperty(key)) {
    console.log(`${key}: ${obj[key]}`);
  }
}

Kết quả:

a: 1
b: 2

Tóm tắt

  • Chúng tôi đã giới thiệu các trường hợp sử dụng hiệu quả cho việc lọc đối tượng và xử lý đối tượng lồng nhau.
  • Sử dụng hasOwnProperty() để tránh các vấn đề do kế thừa prototype gây ra.

6. Các lỗi thường gặp với câu lệnh for…in và cách khắc phục chúng [Beginner-Friendly]

1. Ví dụ lỗi 1|Các thuộc tính prototype được liệt kê

const obj = { a: 1, b: 2 };
Object.prototype.c = 3;

for (const key in obj) {
  console.log(key, obj[key]);
}

Kết quả:

a 1
b 2
c 3

Giải pháp:

for (const key in obj) {
  if (obj.hasOwnProperty(key)) {
    console.log(key, obj[key]);
  }
}

2. Ví dụ lỗi 2|Sử dụng for…in với mảng

const arr = [10, 20, 30];
Array.prototype.extra = "Additional data";

for (const index in arr) {
  console.log(index, arr[index]);
}

Kết quả:

0 10
1 20
2 30
extra undefined

Giải pháp:

for (const value of arr) {
  console.log(value);
}

3. Ví dụ lỗi 3|Xử lý các giá trị undefined

const obj = { a: 1, b: undefined, c: 3 };

for (const key in obj) {
  console.log(key, obj[key]);
}

Giải pháp:

for (const key in obj) {
  const value = obj[key] ?? "Default value";
  console.log(key, value);
}

Tóm tắt

  • Vấn đề thuộc tính prototype: Sử dụng hasOwnProperty().
  • Xử lý mảng: Ưu tiên for…of hoặc forEach.
  • Xử lý giá trị undefined: Gán giá trị mặc định.

7. Kiểm tra hiệu năng của câu lệnh for…in và các phương pháp thay thế

1. So sánh hiệu năng

for…in:

const obj = { a: 1, b: 2, c: 3 };
console.time("for...in");
for (const key in obj) {
  console.log(key, obj[key]);
}
console.timeEnd("for...in");

Object.keys():

console.time("Object.keys");
Object.keys(obj).forEach(key => {
  console.log(key, obj[key]);
});
console.timeEnd("Object.keys");

2. Ví dụ kết quả so sánh

for...in: 0.015ms
Object.keys: 0.005ms

3. Các phương pháp được đề xuất

  • Xử lý đối tượng: Đề xuất sử dụng Object.keys().
  • Xử lý mảng: for…of hoặc forEach nhanh hơn và an toàn hơn.

Tóm tắt

  • Câu lệnh for…in tiện lợi, nhưng bạn nên chọn cú pháp phù hợp dựa trên yêu cầu về hiệu năng và độ an toàn.

8. Tóm tắt|Hiểu câu lệnh for…in và các bước tiếp theo

1. Những điểm chính rút ra từ bài viết này

  1. Cú pháp cơ bản và mục đích của câu lệnh for…in:
  • Được dùng để lặp qua tên các thuộc tính của một đối tượng.
  • Chuyên dùng để xử lý các khóa của đối tượng thay vì mảng.
  1. Các lưu ý quan trọng khi sử dụng với mảng:
  • Thứ tự không được đảm bảo, và các thuộc tính trong chuỗi prototype có thể được liệt kê.
  • Đối với xử lý mảng, for…of hoặc forEach() được khuyến nghị.
  1. Sự khác biệt giữa for…in và for…of:
  • for…in: Liệt kê tên các thuộc tính (keys).
  • for…of: Xử lý trực tiếp các giá trị của mảng và các đối tượng có thể lặp.
  1. Sử dụng nâng cao và các thực hành tốt:
  • Xử lý các đối tượng lồng nhau bằng đệ quy.
  • Loại trừ kế thừa prototype bằng cách sử dụng hasOwnProperty() .
  • Cải thiện hiệu năng và độ an toàn với các phương pháp thay thế như Object.keys()Object.entries() .
  1. Tối ưu hoá hiệu năng:
  • Object.keys() + forEach() được đề xuất như một lựa chọn thay thế cho for…in vì nó đảm bảo thứ tự và mang lại hiệu năng tốt hơn.

2. Câu trả lời cho các câu hỏi thường gặp

Câu hỏi 1. Có nên tránh sử dụng câu lệnh for…in không?

  • Đáp: Nó phù hợp để liệt kê các thuộc tính của đối tượng, nhưng đối với mảng hoặc các tác vụ yêu cầu hiệu năng cao, các phương pháp khác như for…of hoặc Object.keys() an toàn và hiệu quả hơn.

Câu hỏi 2. Vấn đề liệt kê thuộc tính prototype có luôn xảy ra không?

  • Đáp: Có. Theo đặc tả, các thuộc tính kế thừa từ prototype sẽ được bao gồm. Để tránh điều này, bạn phải sử dụng hasOwnProperty() .

Câu hỏi 3. Vòng lặp nào là tốt nhất tùy theo mảng hay đối tượng?

  • Đáp:
  • Đối tượng: Sử dụng for…in hoặc Object.keys() .
  • Mảng: Sử dụng for…of hoặc forEach() .

3. Các bước tiếp theo|Các chủ đề cần học thêm

  1. Các đối tượng có thể lặp và iterable:
  • Các cấu trúc dữ liệu như Map, Set, WeakMap và WeakSet, và các cấu trúc vòng lặp để xử lý chúng.
  1. Xử lý dữ liệu với các hàm bậc cao:
  • Cách sử dụng và ví dụ thực tế của map(), filter() và reduce() .
  1. Kỹ thuật nâng cao cho đối tượng và mảng:
  • Xử lý dữ liệu bằng Object.values()Object.entries() .
  1. Các tính năng hiện đại của JavaScript:
  • Cú pháp ngắn gọn sử dụng các tính năng ES6+ như spread operators và destructuring .
  1. Xử lý bất đồng bộ với Promise / Async / Await:
  • Áp dụng các khái niệm này vào xử lý thời gian thực liên quan đến việc lấy dữ liệu và thao tác đối tượng động.

4. Kết luận|Làm chủ việc xử lý vòng lặp trong JavaScript

Bài viết này tập trung vào câu lệnh for…in trong JavaScript, bao quát mọi thứ từ cách sử dụng cơ bản đến các ví dụ nâng cao, những bẫy cần tránh và các phương pháp thay thế.

Những điểm quan trọng nhất:

  • Câu lệnh for…in phù hợp để liệt kê các thuộc tính của đối tượng, nhưng nên chọn các phương pháp thay thế cho việc xử lý mảng hoặc các kịch bản yêu cầu hiệu năng cao.
  • Để ngăn ngừa lỗi và hành vi không mong muốn, việc luôn tuân thủ các thực hành tốt nhất và các biện pháp an toàn khi viết mã là rất quan trọng.

Tiếp tục đến Bước Tiếp Theo!
Nâng cao hiểu biết của bạn về các phương pháp thay thế và các hàm bậc cao được giới thiệu trong bài viết này để đưa kỹ năng JavaScript của bạn lên một tầm cao mới.

広告