我被告知不要使用。。。在JavaScript中使用数组。为什么不呢?
当前回答
虽然这个问题没有特别提到,但我想补充一点,有一个很好的理由永远不要使用。。。在中使用NodeList(就像从querySelectorAll调用中获得的那样,因为它根本看不到返回的元素,而只在NodeListneneneba属性上迭代。
在单个结果的情况下,我得到:
var nodes = document.querySelectorAll(selector);
nodes
▶ NodeList [a._19eb]
for (node in nodes) {console.log(node)};
VM505:1 0
VM505:1 length
VM505:1 item
VM505:1 entries
VM505:1 forEach
VM505:1 keys
VM505:1 values
这解释了为什么我的for(节点中的节点)node.href=newLink;正在失败。
其他回答
以下是这种做法(通常)不好的原因:
对于in循环迭代它们自己的所有可枚举财产及其原型的可枚举财产。通常在数组迭代中,我们只需要迭代数组本身。即使您自己可能没有向数组中添加任何内容,但您的库或框架可能会添加一些内容。
例子:
Array.prototype.hithere=“此处”;var数组=[1,2,3];for(let el in array){//hithere属性也将被迭代控制台日志(el);}
对于in循环不能保证特定的迭代顺序。尽管现在大多数现代浏览器中通常都能看到isorder,但仍然没有100%的保证。对于in循环忽略未定义的数组元素,即尚未分配的数组元素。
例子::
常量arr=[];arr[3]=“foo”;//将阵列大小调整为4arr[4]=未定义;//添加另一个未定义值的元素//遍历数组,for循环确实显示了未定义的元素for(设i=0;i<arr.length;i++){控制台日志(arr[i]);}console.log('\n');//for in忽略未定义的元素for(let el in arr){控制台日志(arr[el]);}
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上的循环中:”);
孤立地说,在数组中使用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。
一个重要的方面是。。。in-only迭代包含在对象中的财产,该对象的可枚举属性属性设置为true。因此,如果尝试使用for对对象进行迭代。。。然后,如果任意财产的可枚举属性为false,则可能会丢失这些属性。很有可能更改普通Array对象的可枚举属性属性,以便不枚举某些元素。虽然一般来说,属性属性倾向于应用于对象中的函数财产。
可以通过以下方式检查财产的可枚举属性属性的值:
myobject.propertyIsEnumerable('myproperty')
或获取所有四个属性属性:
Object.getOwnPropertyDescriptor(myobject,'myproperty')
这是ECMAScript 5中提供的一个特性——在早期版本中,无法更改可枚举属性属性的值(它总是设置为true)。
因为如果你不小心的话,它会迭代属于原型链上对象的财产。
您可以使用。。在中,只需确保使用hasOwnProperty检查每个属性。