我被告知不要使用。。。在JavaScript中使用数组。为什么不呢?


当前回答

A代表。。。in循环总是枚举键。对象财产键始终是String,甚至是数组的索引财产:

var myArray = ['a', 'b', 'c', 'd'];
var total = 0
for (elem in myArray) {
  total += elem
}
console.log(total); // 00123

其他回答

由于JavaScript元素保存为标准对象财产不建议使用for…遍历JavaScript数组。。。在里面循环,因为普通元素和所有可枚举的财产上市的

从…起https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Indexed_collections

有三个原因你不应该使用。。在中迭代数组元素:

对于in将循环遍历数组对象的所有自己和继承的财产,这些属性不是DontEnum;这意味着,如果有人将财产添加到特定数组对象(这有合理的原因-我自己做过)或更改array.prototype(这在代码中被认为是错误的做法,应该与其他脚本一起工作),这些财产也会被迭代;通过检查hasOwnProperty()可以排除继承的财产,但这对数组对象本身中设置的财产没有帮助对于中不能保证保留元素顺序它的速度很慢,因为您必须遍历数组对象的所有财产及其整个原型链,并且仍然只能获取属性的名称,即要获取值,需要进行额外的查找

对于在处理JavaScript中的对象时,in是有用的,但对Array来说不是,但我们仍然不能说这是错误的方法,但不建议这样做,请看下面的示例,使用for。。。循环中:

let txt = "";
const person = {fname:"Alireza", lname:"Dezfoolian", age:35}; 
for (const x in person) {
    txt += person[x] + " ";
}
console.log(txt); //Alireza Dezfoolian 35 

好了,让我们现在使用Array:

let txt = "";
const person = ["Alireza", "Dezfoolian", 35]; 
for (const x in person) {
   txt += person[x] + " ";
}
console.log(txt); //Alireza Dezfoolian 35 

正如你看到的结果一样。。。

但让我们尝试一下,让我们为Array原型。。。

Array.prototype.someoneelse = "someoneelse";

现在我们创建一个新的Array();

let txt = "";
const arr = new Array();
arr[0] = 'Alireza';
arr[1] = 'Dezfoolian';
arr[2] = 35;
for(x in arr) {
 txt += arr[x] + " ";
}
console.log(txt); //Alireza Dezfoolian 35 someoneelse

你看到别人了!!!。。。在本例中,我们实际上循环通过新的Array对象!

这就是为什么我们需要使用。。小心,但情况并非总是这样。。。

孤立地说,在数组中使用for没有错。For-in迭代对象的属性名,在“现成”数组的情况下,财产对应于数组索引。(像length、toString等内置属性不包含在迭代中。)

然而,如果您的代码(或您正在使用的框架)将自定义财产添加到数组或数组原型中,那么这些财产将包含在迭代中,这可能不是您想要的。

一些JS框架,如Prototype修改了Array原型。像JQuery这样的其他框架则不然,因此使用JQuery,您可以在中安全地使用。

如果你有疑问,你可能不应该使用。

迭代数组的另一种方法是使用for循环:

for (var ix=0;ix<arr.length;ix++) alert(ix);

然而,这有一个不同的问题。问题是JavaScript数组可能有“洞”。如果您将arr定义为:

var arr = ["hello"];
arr[100] = "goodbye";

然后数组有两个项目,但长度为101。在中使用for将产生两个索引,而for循环将产生101个索引,其中99的值为undefined。

TL&DR:在数组中使用for in循环并不是坏事,事实上恰恰相反。

我认为如果在数组中正确使用,for in循环是JS的瑰宝。你应该完全控制你的软件,并知道你在做什么。让我们看看上面提到的缺点,并逐一反驳它们。

它还遍历继承的财产:首先,对Array.prototype的任何扩展都应该使用Object.defineProperty()完成,并且它们的可枚举描述符应该设置为false。任何没有这样做的库都不应该被使用。添加到继承链中的财产稍后会被计数:当按Object.setPrototypeOf或按类扩展进行数组子分类时。您应该再次使用Object.defineProperty(),它默认将可写、可枚举和可配置的属性描述符设置为false。让我们在这里看到一个数组子类示例。。。

函数堆栈(…a){var stack=新数组(…a);Object.setPrototypeOf(堆栈,stack.prototype);返回堆栈;}Stack.prototype=对象.create(Array.prototype);//现在堆栈可以完全访问数组方法。Object.defineProperty(Stack.prototype,“constructor”,{value:Stack});//现在Stack是一个合适的构造函数Object.defineProperty(Stack.prototype,“peak”,{value:function(){//将Stack“only”方法添加到Stack.prototype。返回this[this.length-1];}});var s=新堆栈(1,2,3,4,1);console.log(s.peak());s[s.length]=7;console.log(“长度:”,s.length);s.push(42);console.log(JSON.stringify);console.log(“长度:”,s.length);for(var i in s)console.log(s[i]);

所以你看。。因为您关心代码,所以in循环现在是安全的。

for in循环很慢:见鬼,没有。如果你在不时需要的稀疏数组上循环,这是迄今为止最快的迭代方法。这是人们应该知道的最重要的表演技巧之一。让我们看一个例子。我们将在稀疏数组上循环。

变量a=[];a[0]=“零”;a[10000000]=“1000万”;console.time(“用于数组a上的循环:”);对于(var i=0;i<a.length;i++)a[i]&&console.log(a[i]);console.timeEnd(“用于数组a上的循环:”);console.time(“用于数组a上的循环:”);对于(a中的var i)a[i]&&console.log(a[i]);console.timeEnd(“用于数组a上的循环中:”);