我在我的JavaScript文件中使用了JSLint。它抛出了错误:
for( ind in evtListeners ) {
第41行的问题第9条:for的身体应该是 包含在if语句中以过滤不需要的 原型中的属性。
这是什么意思?
答案 0 :(得分:404)
首先,从不使用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]
这是扩展对象和添加新方法的标准方法。很多图书馆都这样做。
但是,让我们看看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 in
和for 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
答案 1 :(得分:85)
jslint的作者道格拉斯·克罗克福德曾多次撰写(和发言)这个问题。他网站的this页面上有一节介绍了这一点:
for Statement
一类陈述应该有 以下表格:
for (initialization; condition; update) { statements } for (variable in object) { if (filter) { statements } }
第一个表格应该与。一起使用 数组和一个循环 可预先确定的迭代次数。
第二种形式应该与 对象。请注意那些成员 被添加到原型中 对象将被包含在 列举。编程是明智的 在防守上使用 hasOwnProperty方法来区分 对象的真正成员:
for (variable in object) { if (object.hasOwnProperty(variable)) { statements } }
Crockford还有一个关于YUI剧院的视频系列,在那里他谈到这一点。如果你对javascript稍微认真一点,Crockford关于javascript的一系列视频/谈话是必须要看的。
答案 2 :(得分:9)
Vava的回答是正确的。如果您使用jQuery,那么$.each()
函数会处理这个问题,因此使用起来更安全。
$.each(evtListeners, function(index, elem) {
// your code
});
答案 3 :(得分:7)
@all - JavaScript中的所有东西都是一个object(),所以像“只在对象上使用它”之类的语句有点误导。另外JavaScript不是强类型的,因此1 ==“1”为真(虽然1 ===“1”不是,Crockford对此很重要)。当谈到JS中数组的概念性概念时,在定义中输入很重要。
@Brenton - 不需要成为术语独裁者; “关联数组”,“字典”,“哈希”,“对象”,这些编程概念都适用于JS中的一个结构。它是名称(键,索引)值对,其中值可以是任何其他对象(字符串也是对象)
所以,
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]);
}
}
答案 4 :(得分:2)
当然,说起来有点极端
...永远不要使用for循环 枚举数组。决不。使用 (var i = 0; I&LT; arr.length;我++)
值得强调道格拉斯克罗克福德提取物中的部分
......第二种形式应该与。一起使用 对象...
如果需要一个关联数组(也就是哈希表/字典),其中键被命名而不是数字索引,则必须将其作为对象实现,例如var myAssocArray = {key1: "value1", key2: "value2"...};
。
在这种情况下,myAssocArray.length
将显示为null(因为此对象没有'length'属性),并且您的i < myAssocArray.length
不会让您走得太远。除了提供更大的便利之外,我希望关联数组在许多情况下提供性能优势,因为数组键可以是有用的属性(即数组成员的ID属性或名称),这意味着您不必迭代冗长数组重复评估if语句以查找您所追求的数组条目。
无论如何,还要感谢JSLint错误消息的解释,我将在通过我的无数关联数组进行交互时使用'isOwnProperty'检查!
答案 5 :(得分:0)
这意味着您应该使用hasOwnProperty method过滤evtListeners的属性。
答案 6 :(得分:0)
为了补充in / for / $。each的主题,我添加了一个jsperf测试用例,用于使用$ .each vs for:http://jsperf.com/each-vs-for-in/2
不同的浏览器/版本以不同的方式处理它,但似乎$ .each和直接输入是性能最便宜的选项。
如果你正在使用in来迭代一个关联数组/对象,知道你在追求什么并忽略其他一切,如果你使用jQuery,则使用$ .each,或者只使用in(然后中断;一次;你达到了你应该知道的应该是最后一个元素)
如果你正在迭代一个数组来执行其中每个键对的某些事情,如果你不使用jQuery则应该使用hasOwnProperty方法,如果你使用jQuery则使用$ .each。
如果您不需要关联数组,请始终使用for(i=0;i<o.length;i++)
... lol chrome的执行速度比in $.each
快97%