Trước hết, bao giờ sử dụng một vòng lặp for in
liệt kê trên một mảng. Không bao giờ. Sử dụng tốt cũ for(var i = 0; i<arr.length; i++)
.
Lý do đằng sau điều này là như sau: mỗi đối tượng trong JavaScript có một trường đặc biệt được gọi là prototype
. Mọi thứ bạn thêm vào trường đó sẽ có thể truy cập được trên mọi đối tượng thuộc loại đó. Giả sử bạn muốn tất cả các mảng có một hàm mới tuyệt vời được gọi là filter_0
sẽ lọc các số không.
Array.prototype.filter_0 = function() {
var res = [];
for (var i = 0; i < this.length; i++) {
if (this[i] != 0) {
res.push(this[i]);
}
}
return res;
};
console.log([0, 5, 0, 3, 0, 1, 0].filter_0());
//prints [5,3,1]
Đây là cách tiêu chuẩn để mở rộng đối tượng và thêm phương pháp mới. Rất nhiều thư viện làm điều này. Tuy nhiên, chúng ta hãy nhìn vào cách for in
làm việc bây giờ:
var listeners = ["a", "b", "c"];
for (o in listeners) {
console.log(o);
}
//prints:
// 0
// 1
// 2
// filter_0
Bạn có thấy? Nó đột nhiên nghĩ rằng filter_0 là một chỉ số mảng khác. Tất nhiên, nó không thực sự là một chỉ số, nhưng for in
liệt kê thông qua các trường đối tượng, không chỉ là các chỉ mục số. Vì vậy, chúng tôi hiện đang liệt kê tất cả các chỉ số số vàfilter_0
. Nhưng filter_0
không phải là một trường của bất kỳ đối tượng mảng cụ thể nào, mỗi đối tượng mảng đều có thuộc tính này ngay bây giờ.
May mắn thay, tất cả các đối tượng đều có phương thức hasOwnProperty
, kiểm tra xem trường này có thực sự thuộc về đối tượng hay không hoặc chỉ đơn giản là được thừa kế từ chuỗi nguyên mẫu và do đó thuộc về tất cả các đối tượng thuộc loại đó.
for (o in listeners) {
if (listeners.hasOwnProperty(o)) {
console.log(o);
}
}
//prints:
// 0
// 1
// 2
Lưu ý, rằng mặc dù mã này làm việc như mong đợi cho mảng, bạn nên không bao giờ, không bao giờ , sử dụng for in
và for each in
cho mảng. Hãy nhớ rằng for in
liệt kê các trường của một đối tượng, không phải chỉ mục hoặc giá trị mảng.
var listeners = ["a", "b", "c"];
listeners.happy = "Happy debugging";
for (o in listeners) {
if (listeners.hasOwnProperty(o)) {
console.log(o);
}
}
//prints:
// 0
// 1
// 2
// happy
theo mặc định 'trong' lặp trên tài sản thừa kế là tốt. Thông thường, phần thân được bọc trong 'if (evtListeners.hasOwnProperty (ind))' để hạn chế việc xử lý chỉ với các thuộc tính riêng (không được kế thừa). Tuy nhiên, trong một số trường hợp, bạn thực sự muốn lặp qua tất cả các thuộc tính, bao gồm cả các thuộc tính được kế thừa. Trong trường hợp đó, JSLint buộc bạn quấn thân vòng lặp trong câu lệnh if để quyết định thuộc tính nào bạn thực sự muốn. Điều này sẽ làm việc và làm cho JSlint hạnh phúc: 'if (evtListeners [ind]! == undefined)' – xorcus
Hầu hết các câu trả lời đều lỗi thời. một giải pháp được cập nhật có thể được tìm thấy tại https://stackoverflow.com/a/10167931/3138375 –