为什么FileList对象不是数组?

138

3
许多与DOM和HTML相关的API以更加数据结构无关的方式进行定义。比如NodeListHTMLCollection,例如:如果一种语言不支持foo[bar]语法,会发生什么? - Felix Kling
4个回答

175

可能有几个原因。首先,如果它是一个数组,你可以修改它。但你不能修改 FileList 实例。其次但相关的是,它可能是(很可能是)浏览器数据结构的视图,因此最小的功能集使实现更容易提供。

您可以通过 a = Array.from(theFileList)(这是 ES2015 的方法,但轻松地可以 polyfill)或通过 a = Array.prototype.slice.call(theFileList) 将其转换为数组。

2018 年更新:有趣的是,规范FileList 有一个注释:

应将 FileList 接口视为“风险”,因为 Web 平台上的一般趋势是使用 ECMAScript [ECMA-262] 中的 Array 平台对象替换这些接口。特别是,这意味着类似 filelist.item(0) 的语法存在风险;FileList 的大多数其他编程用途不太可能受到迁移到 Array 类型的影响。

我觉得这个注释很奇怪。我认为趋势是朝向 iterable,而不是 Array — 例如将 NodeList 更新为 iterable,以便与扩展语法、for-offorEach 兼容。


6
既然不能修改它,那么它就没必要有.push()和其他数组方法。 - Val Kornea
2
@VladimirKornea(时间流逝,但是...)好的,我有一个验证文件大小的用例,因此“Array”中的“filter”非常方便。还有许多其他的“只读”方法。 - estani
这个注释的意思是使用 Array.from(theFileList) 会有风险吗?谢谢你的帮助! - Crashalot
@Crashalot - 不,那应该没问题的。我想象不到FileList本身会消失(尽管我可能是错的——注意事项说,大多数人的代码把它当作一个数组处理),但显然item方法可能会因为没有被广泛使用而消失。但对象会存在,并且类似于数组,所以从可能发生变化的东西(FileList)转换到一个良好定义的东西(一个数组)可以使用Array.from(theFileList) - T.J. Crowder
1
感谢您的快速回复和澄清。好的,我们将坚持使用 Array.from(theFileList),因为它不是一个真正的数组,而我们需要它作为一个数组来进行连接。 - Crashalot

27

我认为它是属于自己的数据类型,因为在定义它时面向对象编程比函数式编程更流行。现代JavaScript提供将类似数组的数据类型转换为数组的功能。

例如,就像Tim所描述的那样: const files = [...filesList]

ES6中迭代FileList的另一种方法是使用Array.from()方法。

const fileListAsArray = Array.from(fileList)

在我看来,这种方式比展开运算符更易读,但另一方面,代码更长:)


确实,他们试图让JS看起来像Java的愚蠢的小兄弟。我认为,这里并不是OO的问题 - 具有讽刺意味的是,在许多方面,Java本身在面向对象方面并不非常一致。我会争辩说FileList不是一个数组,从面向对象的角度来看这是值得质疑的。其他一些东西也是如此,比如有一个专门的Math对象(在Java中这样做有点意义),即使只有JS的数字类型,这也可以做得更好。我想这都是匆忙设计的后果。 - Oliver Schimmer

7
如果你想在FileList上使用数组方法,可以尝试使用apply
例如: Array.prototype.every.call(YourFileList, file => { ... }) 如果你想使用every方法。

2
以下是为File添加toObject()函数和为FileList添加toArray()函数的一些polyfill示例:
File.prototype.toObject = function () {
  return Object({
    lastModified: parseInt(this.lastModified),
    lastModifiedDate: String(this.lastModifiedDate),
    name: String(this.name),
    size: parseInt(this.size),
    type: String(this.type)
  })
}

FileList.prototype.toArray = function () {
  return Array.from(this).map(function (file) {
    return file.toObject()
  })
}

var files = document.getElementById('file-upload').files
var fileObject = files[0].toObject()
var filesArray = files.toArray()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接