Trước hết, không bao giờ sử dụng một for in
vòng lặp để liệt kê trên một mảng. Không bao giờ. Dùng cũ tốt 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 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 thú vị đượ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à một cách tiêu chuẩn để mở rộng các đối tượng và thêm các phương thức mới. Rất nhiều thư viện làm điều này. Tuy nhiên, hãy xem cách làm for in
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 bộ lọc_0 là một chỉ mục mảng khác. Tất nhiên, nó không thực sự là một chỉ mục số, nhưng for in
liệt kê thông qua các trường đối tượng, không chỉ các chỉ mục số. Vì vậy, bây giờ chúng tôi liệt kê thông qua mọi chỉ 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.
May mắn thay, tất cả các đối tượng đều có một hasOwnProperty
phương thức, kiểm tra xem trường này có thực sự thuộc về chính đối tượng đó hay không nếu nó được kế thừa 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 ý, mặc dù mã này hoạt động như mong đợi cho mảng, bạ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 các 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
if (evtListeners.hasOwnProperty(ind))
để hạn chế xử lý chỉ sở hữu các thuộc tính (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 lại 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 phải bọc thân vòng lặp trong một câu lệnh if để quyết định các thuộc tính nào bạn thực sự muốn. Điều này sẽ hoạt động và làm cho JSlint hạnh phúc:if (evtListeners[ind] !== undefined)