什么是JSLint错误“一个for的内容应包裹在一个if语句”是什么意思?

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

for( ind in evtListeners ) { 

第41行的问题字符9:for的主体应该包装在if语句中,以过滤来自原型的不需要的属性。

这是什么意思?

首先, 不要使用for in循环枚举数组。 决不。 使用古老for(var i = 0; i<arr.length; i++)

其原因如下:JavaScript中的每个对象都有一个称为prototype的特殊字段。 您添加到该字段的所有内容都可以在该types的每个对象上访问。 假设你想要所有的数组都有一个叫做filter_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方法,它检查这个字段是否真的属于这个对象本身,或者它是否从原型链inheritance而来,因此属于这个types的所有对象。

 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)多次就这个问题写了(也是讲过)。 他的网站上有一节介绍了这一点:

声明

A类报表应该有以下forms:

 for (initialization; condition; update) { statements } for (variable in object) { if (filter) { statements } } 

第一种forms应该与数组一起使用,并且使用可预定数量迭代的循环。

第二种forms应该与对象一起使用。 请注意,添加到对象原型的成员将包含在枚举中。 通过使用hasOwnProperty方法来区分对象的真实成员,防御性编程是明智的:

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

克罗克福德在YUI剧院也有一个关于这个的video系列。 Crockford的一系列关于javascript的video/演讲是一个必须看到,如果你甚至对JavaScript稍微认真。

不好:(jsHint会抛出一个错误)

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

好:

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

瓦瓦的答案是在标记上。 如果你使用jQuery,那么$.each()函数会处理这个问题,因此使用起来更安全。

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

@all – JavaScript中的所有东西都是对象(),所以像“只在对象上使用”这样的语句有点误导。 另外JavaScript没有强types,所以1 ==“1”是真的(尽pipe1 ===“1”不是,Crockford在这方面很大)。 当涉及JS中数组的整数概念时,键入在定义中很重要。

@布伦顿 – 不需要成为一个术语独裁者; “关联数组”,“字典”,“哈希”,“对象”,这些编程概念都适用于JS中的一个结构。 它是名称(键,索引)值对,其中值可以是任何其他对象(string也是对象)

所以, new Array()[]是一样的

new Object()大致类似于{}

 var myarray = []; 

创build一个结构,该结构是所有索引(又名键)必须是整数的限制的数组。 它还允许通过.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]); } } 

也许不是一个数组的最佳用法,但只是一个例子,事情并不总是clearcut。

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

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

当然有点极端的说法

…从不使用for循环枚举数组。 决不。 使用旧的(var i = 0;我<arr.length; i ++)

值得强调道格拉斯·克罗克福德(Douglas Crockford)提炼部分

…第二种forms应该与对象一起使用…

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

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

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

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

为了添加in / for / $。每个主题,我添加了一个jsperftesting用例,使用$ .each vs for在: http ://jsperf.com/each-vs-for-in/2

不同的浏览器/版本以不同的方式处理它,但似乎是$。每个和每个版本都是性能最便宜的选项。

如果你使用in来遍历一个关联的数组/对象,知道你在做什么,并忽略其他的一切,如果你使用jQuery,或者仅仅用于in,那么使用$ .each(然后rest一下;一旦你达到你所知道的最后一个要素)

如果你迭代一个数组来执行其中的每个键对,那么如果你不使用jQuery,应该使用hasOwnProperty方法,如果你使用jQuery,则使用$ .each。

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