JSLint错误'for的主体应该包含在if语句中'是什么意思?

jrh*_*ath 236 javascript jslint

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

for( ind in evtListeners ) {
Run Code Online (Sandbox Code Playgroud)

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

这是什么意思?

vav*_*ava 417

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

这背后的原因如下:JavaScript中的每个对象都有一个名为的特殊字段prototype.您添加到该字段的所有内容都将在该类型的每个对象上都可访问.假设您希望所有数组都有一个很酷的新函数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]
Run Code Online (Sandbox Code Playgroud)

这是扩展对象和添加新方法的标准方法.很多图书馆都这样做.但是,让我们来看看for in现在的工作原理:

var listeners = ["a", "b", "c"];
for (o in listeners) {
    console.log(o);
}
//prints:
//  0
//  1
//  2
//  filter_0
Run Code Online (Sandbox Code Playgroud)

你有看到?它突然认为filter_0是另一个数组索引.当然,它不是真正的数字索引,而是for in通过对象字段枚举,而不仅仅是数字索引.所以我们现在正在枚举每个数字索引 filter_0.但是filter_0不是任何特定数组对象的字段,每个数组对象现在都具有此属性.

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

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

请注意,尽管此代码可以按预期的方式运行,但您永远应该使用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
Run Code Online (Sandbox Code Playgroud)

  • 你不应该使用`for in`迭代数组,因为语言并没有改变`for in`将枚举数组的顺序.它可能不是数字顺序.另外,如果你使用`for(i = 0; i <array.length; i ++)样式结构,你可以确保你只是*按顺序迭代数字索引,而不是字母数字属性. (40认同)
  • 但是,对于in,可以迭代对象的属性.OP从未说过for in应用于数组.hasOwnProperty是最佳实践,但是有些情况下您不需要它 - 例如,如果一个对象扩展另一个,并且您想要列出对象和'父'一个属性. (12认同)
  • 我认为,不要让人们远离`for-in`循环(顺便说一句,这很棒),我们应该教育他们如何工作(在这个答案中正确完成)并将它们引入[`Object.defineProperty() `](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty)因此他们可以安全地扩展原型而不会破坏任何东西.顺便说一下,如果没有`Object.defineProperty`,扩展本机对象的原型应该不会这样做. (3认同)

Bre*_*ton 86

jslint的作者道格拉斯·克罗克福德曾多次撰写(和发言)这个问题.他网站的这个页面上有一节介绍了这个:

声明

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

for (initialization; condition; update) {
    statements
}

for (variable in object) {
    if (filter) {
        statements
    } 
}
Run Code Online (Sandbox Code Playgroud)

第一种形式应该与数组一起使用,并且具有可预先确定的迭代次数的循环.

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

for (variable in object) {
    if (object.hasOwnProperty(variable)) {
        statements
    } 
}
Run Code Online (Sandbox Code Playgroud)

Crockford还有一个关于YUI剧院的视频系列,在那里他谈到这个.如果你对javascript有点认真的话,Crockford关于javascript的一系列视频/谈话是必须要看的.


Blu*_*ari 18

不好:(jsHint会抛出错误)

for (var name in item) {
    console.log(item[name]);
}
Run Code Online (Sandbox Code Playgroud)

好:

for (var name in item) {
  if (item.hasOwnProperty(name)) {
    console.log(item[name]);
  }
}
Run Code Online (Sandbox Code Playgroud)


HRJ*_*HRJ 9

Vava的回答很明显.如果您使用jQuery,那么该$.each()函数会处理这个问题,因此使用起来更安全.

$.each(evtListeners, function(index, elem) {
    // your code
});
Run Code Online (Sandbox Code Playgroud)

  • 如果在这里考虑性能,我不建议使用`$ .each`(或underscore.js的`_.each`),如果你可以使用原始`for`循环.jsperf有[一些令人大开眼界的对比测试](http://jsperf.com/each-vs-each-vs-for-in)值得一试. (5认同)
  • 这个(http://jsperf.com/each-vs-each-vs-for-in/3)更实际,因为它采用了基本的原型过滤器 (3认同)

小智 7

@all - JavaScript中的所有东西都是一个object(),所以像"只在对象上使用它"之类的语句有点误导.另外JavaScript不是强类型的,因此1 =="1"为真(虽然1 ==="1"不是,Crockford对此很重要).当谈到JS中数组的概念性概念时,键入在定义中很重要.

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

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

new Object() 与...大致相似 {}

var myarray = [];
Run Code Online (Sandbox Code Playgroud)

创建一个结构,该结构具有所有索引(也称为键)必须是整数的限制.它还允许通过.push()自动分配新索引

var myarray = ["one","two","three"];
Run Code Online (Sandbox Code Playgroud)

确实最好处理过 for(initialization;condition;update){

但是关于:

var myarray = [];
myarray[100] = "foo";
myarray.push("bar");
Run Code Online (Sandbox Code Playgroud)

试试这个:

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]);
    }
}
Run Code Online (Sandbox Code Playgroud)

也许不是阵列的最佳用法,而只是说明事情并不总是清晰的.

如果你知道你的密钥,并且肯定是不是整数,你唯一的数组就像结构选项一样.

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


Mel*_*hia 7

诚实地添加一整行只是为了检查键是否存在,同时使用应该迭代对象键的语法是毫无用处的for .. in。就用Object.keys(obj).forEach(key => {}代替吧。