for-in循环遍历Files对象时遍历次数超出实际长度问题求助
问题原因与解决方案
嘿,这个问题我之前也帮人排查过,核心原因是你对FileList对象和for-in循环的特性理解有点偏差,我给你一步步拆解:
为什么会出现多余的循环和奇怪的输出?
你拿到的files是一个**FileList类数组对象**,它不是真正的JavaScript数组,只是长得像数组(有length属性、能通过索引访问元素)。而for-in循环的作用是遍历对象的所有可枚举属性——包括原型链上继承来的属性,这就是问题的根源:
FileList的原型上自带item方法(用于通过索引获取文件),这个方法是可枚举的,所以for-in会遍历到它,这就是你看到file nameitem的原因;- 除此之外,还有一些其他内置的非索引属性会被遍历到,这些属性对应的
files[file]不是File对象,自然就会出现file nameundefined的输出; - 只有
0这个索引属性才对应你选中的Test.txt文件,所以真正有效的循环项只有1次,但for-in把所有可枚举属性都走了一遍,导致循环次数远大于files.length。
另外还要纠正你代码里的一个小错误:File对象继承自Blob,直接把file传给formData.append()就可以了,不需要访问.data属性,这个属性是不存在的哦。
正确的遍历方式
推荐下面几种靠谱的方案:
1. 普通for循环(兼容性最好)
这是最稳妥的方式,因为我们已经知道FileList的长度,直接按索引遍历:
var files = document.getElementById("filePostInput").files; LogData("files length " + files.length); // 1 var formData = new FormData(); for (var i = 0; i < files.length; i++) { var file = files[i]; formData.append("file", file, file.name); LogData("file name" + file.name); }
2. 转成数组后用forEach(ES6+)
如果你的环境支持ES6,可以用Array.from()或者展开运算符把FileList转成真正的数组,然后用数组的遍历方法:
var files = document.getElementById("filePostInput").files; LogData("files length " + files.length); var formData = new FormData(); // 方式一:Array.from Array.from(files).forEach(file => { formData.append("file", file, file.name); LogData("file name" + file.name); }); // 方式二:展开运算符 [...files].forEach(file => { formData.append("file", file, file.name); LogData("file name" + file.name); });
3. 过滤属性后遍历(不推荐,仅作参考)
如果你一定要用for-in,可以手动过滤出索引属性,确保只处理File对象:
var files = document.getElementById("filePostInput").files; LogData("files length " + files.length); var formData = new FormData(); for (var key in files) { // 只处理数字索引对应的属性,且确保是File对象 if (!isNaN(parseInt(key)) && files[key] instanceof File) { var file = files[key]; formData.append("file", file, file.name); LogData("file name" + file.name); } }
总结
for-in循环是为遍历普通对象的键设计的,不要用它遍历数组或类数组对象,不然很容易踩原型链属性的坑。处理FileList这类类数组对象,优先用普通for循环或者转成数组后用数组的遍历方法,既直观又不容易出错。
内容的提问来源于stack exchange,提问作者Thomas Harris
相关产品推荐
相关产品推荐

