JSLint错误'for in的主体应该包装在if语句中'的意思吗?

我在我的JavaScript文件上使用了JSLint。它抛出错误:

for( ind in evtListeners ) {
第41行第9个字符的问题:for in的正文应该是 包装在if语句中以过滤不需要的

这是什么意思?

133896 次浏览

这意味着你应该用hasOwnProperty方法来过滤evtlistener的属性。

首先,从来没有使用for in循环枚举数组。从来没有。使用好的老for(var i = 0; i<arr.length; i++)

这背后的原因如下:JavaScript中的每个对象都有一个名为prototype的特殊字段。您添加到该字段的所有内容都将在该类型的每个对象上可访问。假设你想让所有数组都有一个很酷的新函数filter_0来过滤掉0。

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]
这是扩展对象和添加新方法的标准方法。很多库都这样做。 但是,现在让我们看看for in是如何工作的
var listeners = ["a", "b", "c"];
for (o in listeners) {
console.log(o);
}
//prints:
//  0
//  1
//  2
//  filter_0

你明白了吗?它突然认为filter_0是另一个数组索引。当然,它不是一个真正的数值索引,但for in枚举对象字段,而不仅仅是数值索引。所以我们现在正在枚举每个数字索引而且 filter_0。但是filter_0不是任何特定数组对象的字段,现在每个数组对象都有这个属性。

幸运的是,所有对象都有一个hasOwnProperty方法,该方法检查该字段是否真的属于对象本身,还是只是从原型链继承而来,因此属于该类型的所有对象。

for (o in listeners) {
if (listeners.hasOwnProperty(o)) {
console.log(o);
}
}
//prints:
//  0
//  1
//  2

注意,虽然这段代码对数组的工作如预期的那样,但你绝不应该,从来没有,对数组使用for infor each in。记住for in枚举对象的字段,而不是数组的索引或值。

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

jslint的作者Douglas Crockford就这个问题写过(也说过)很多次。在他的网站的页面上有一个部分涵盖了这一点:

for语句

A类语句应该有 以下形式:

for (initialization; condition; update) {
statements
}


for (variable in object) {
if (filter) {
statements
}
}
第一种形式应该用with 数组和a的循环

第二种形式应该用with 对象。要意识到成员 添加到原型的 对象将包含在 枚举。编程是明智的 防御上使用 方法进行区分 对象的真成员:

for (variable in object) {
if (object.hasOwnProperty(variable)) {
statements
}
}

Crockford还制作了一个关于YUI剧院的系列视频,在视频中他谈到了这一点。如果你对javascript有点兴趣,一定要看Crockford关于javascript的系列视频/演讲。

瓦瓦的回答很中肯。如果你使用jQuery,那么$.each()函数会处理这个问题,因此使用它更安全。

$.each(evtListeners, function(index, elem) {
// your code
});

当然,这样说有点极端

< p >…永远不要使用for in循环to 枚举数组。从来没有。使用 (var I = 0; i< arr.length;我+ +)< / p >

?

道格拉斯·克罗克福德节选中的这部分值得强调

< p >…第二种形式应该用with 对象…< / p >

如果你需要一个关联数组(又名哈希表/字典),其中键是命名的,而不是数字索引,你将不得不将其实现为一个对象,例如var myAssocArray = {key1: "value1", key2: "value2"...};

在这种情况下,myAssocArray.length将返回null(因为这个对象没有'length'属性),而你的i < myAssocArray.length不会让你走得太远。除了提供更大的便利性之外,我还希望关联数组在许多情况下提供性能优势,因为数组键可以是有用的属性(即数组成员的ID属性或名称),这意味着您不必重复遍历一个冗长的数组来计算if语句以找到您要查找的数组项。

无论如何,也感谢JSLint错误消息的解释,我将使用'isOwnProperty'检查现在通过我的无数关联数组交互!

@all——JavaScript中的所有东西都是一个对象(),所以像“只在对象上使用这个”这样的语句有点误导人。此外,JavaScript不是强类型的,所以1 == "1"是真的(尽管1 === "1"不是真的,Crockford在这方面做得很好)。当涉及到JS中数组的编程概念时,类型在定义中很重要。

@Brenton -没有必要成为术语独裁者;“关联数组”,“字典”,“哈希”,“对象”,这些编程概念都适用于JS中的一个结构。它是name (key, index)值对,其中值可以是任何其他对象(字符串也是对象)

< p >, new Array()[]

相同

new Object()大致类似于{}

var myarray = [];

创建一个数组结构,其中所有索引(即键)必须为整数。它还允许通过.push()自动分配新索引

var myarray = ["one","two","three"];

的确是通过for(initialization;condition;update){最好的处理

但是:

var myarray = [];
myarray[100] = "foo";
myarray.push("bar");

试试这个:

var myarray = [], i;
myarray[100] = "foo";
myarray.push("bar");
myarray[150] = "baz";
myarray.push("qux");
alert(myarray.length);
for(i in myarray){
if(myarray.hasOwnProperty(i)){
alert(i+" : "+myarray[i]);
}
}

也许不是数组的最佳用法,但只是说明事情并不总是明确的。

如果你知道键值,而且肯定不是整数,你唯一的数组类结构选项就是对象。

var i, myarray= {
"first":"john",
"last":"doe",
100:"foo",
150:"baz"
};
for(i in myarray){
if(myarray.hasOwnProperty(i)){
alert(i+" : "+myarray[i]);
}
}

只是添加到for in/for/$的主题。每一个,我添加了一个jsperf测试用例使用$。每个vs for in: http://jsperf.com/each-vs-for-in/2

不同的浏览器/版本处理它的方式不同,但似乎$。每一种都是性能上最便宜的选择。

如果你使用for in来遍历一个关联数组/对象,知道你在寻找什么,忽略其他一切,使用$。每一个如果你使用jQuery,或者只是在(然后休息;一旦你到达了你所知道的最后一个元素)

如果你在一个数组中迭代每个键对来执行一些事情,如果你不使用jQuery,应该使用hasOwnProperty方法,并使用$。每一个如果你使用jQuery。

如果你不需要关联数组,总是使用for(i=0;i<o.length;i++)…lol chrome比for in或$.each快97%

坏的:(jsHint将抛出错误)

for (var name in item) {
console.log(item[name]);
}

好:

for (var name in item) {
if (item.hasOwnProperty(name)) {
console.log(item[name]);
}
}

诚实地说,添加一整行只是为了检查键是否存在,而使用的语法应该是遍历对象的键,这使得for .. in无用。只需使用Object.keys(obj).forEach(key => {}即可。