如何判断我是否有一个 File 对象列表?

How can I tell if I have a list of File objects?

我现在正在处理一些拖放操作,作为规范化步骤,我想检查我拥有的对象列表是否实际上是 Files。看来我通常从 event.dataTransfer 得到的是 FileList / DataTransferFileList,但我正在编写的函数最终可能会接受来自非事件源的 File 对象。所以,我正在考虑检查其中的各个项目是否是 FileDataTransferItem.

的实例

然而,似乎我实际上可以从 JS 中得到的东西到处都是。 MDN tells me that DataTransfer.files contains a FileList; Chrome Devtools shows it as a DataTransferItemList (in the console). An item within the list should be a 'File', according to MDN,但 Devtools 将其显示为 DataTransferItem。奇怪的是,DataTransferItem 在 Devtools 控制台中未定义,并且肯定不适用于 instanceof 调用。不过,FileFileListDataTransferItemList 都在那里。

我什至还没有开始研究其他浏览器....

所以,我的问题分为两部分:

  1. 这些变化是怎么回事? MDN 是否更喜欢 Gecko 的功能而不是对 W3C 规范的解释?我是否在 Devtools 控制台中看到 Webkit 数据类型,但这些数据类型不一定转换为我可以用于 instanceof?

  2. 的 JS 中可访问的任何内容(即 JS 构造函数)
  3. 鉴于所有这些变化,我如何判断某物是否是文件列表?我应该依赖一些鸭子打字解决方案而不是 instanceof 吗?

所以我得到了这样的结果:

var knownFiles = [];

// If not already a list, make it a list
if (!files.length) {
    files = [files];
}

// Iterate manually to accommodate Array, FileList, DataTransferItemList
for (i = 0; i < files.length; i++) {
    file = files[i];

    if (Blob && file instanceof Blob) {
        // Safari, Firefox, IE land here
        knownFiles.push(file);
    } else if (file.webkitGetAsEntry) {
        // Chrome wraps Files in DataTransferItems
        knownFiles.push(file.webkitGetAsEntry());
    }
}

return knownFiles;

其中大部分来自浏览器(Chrome 41、Safari 8、Firefox 36 和 IE 11),但我也从这里得到了一些帮助:https://code.flickr.net/2012/12/10/drag-n-drop/.

显然,Chrome 是唯一一个会为 DataTransferItemList interface 烦恼的浏览器,它在 FileLists 和 Files 周围添加了一个额外的层 [= =14=] 属性 个 drag/drop 个事件。