javascriptroom blog

Why Isn't FileList an Array? Understanding the Object's Limited Properties and Methods

If you’ve ever worked with file uploads in JavaScript, you’ve likely encountered the FileList object. When a user selects files via an <input type="file"> element, the files property of that input returns a FileList—a collection of File objects representing the selected files. At first glance, FileList might seem like an array: it has a length property, and you can access items via index (e.g., fileList[0]). But try calling an array method like map() or filter() on it, and you’ll hit a wall.

So why isn’t FileList an array? This question trips up many developers, especially those new to working with user file inputs. In this blog, we’ll dive into the nature of FileList, compare it to native JavaScript arrays, explore the reasons behind its design, and learn how to work with it effectively using array-like patterns.

2025-11

Table of Contents#

  1. What is FileList?
  2. FileList vs. Array: A Detailed Comparison
  3. Why Isn’t FileList an Array?
  4. Working with FileList as if It Were an Array: Conversion Methods
  5. Common Pitfalls to Avoid
  6. Conclusion
  7. References

What is FileList?#

FileList is a read-only DOM API object that represents a collection of File objects. It is most commonly accessed via the files property of an <input type="file"> element after a user selects files. Each File object in the FileList contains metadata about a selected file, such as its name, size, type, and last modified date.

Example: Obtaining a FileList#

Here’s a simple HTML/JavaScript snippet to retrieve a FileList:

<!-- HTML -->
<input type="file" id="fileInput" multiple> <!-- "multiple" allows selecting multiple files -->
 
<script>
  // Get the input element
  const fileInput = document.getElementById('fileInput');
 
  // Listen for file selection changes
  fileInput.addEventListener('change', (event) => {
    const fileList = event.target.files; // This is the FileList object
    console.log('Selected files:', fileList);
    console.log('Number of files:', fileList.length); // e.g., 2
    console.log('First file name:', fileList[0].name); // e.g., "document.pdf"
  });
</script>

In the console, fileList will appear as an object with a length property and indexed entries (e.g., 0: File, 1: File), but it won’t have array methods like push() or map().

FileList vs. Array: A Detailed Comparison#

To understand why FileList isn’t an array, let’s compare their properties, methods, and behavior.

Properties#

FeatureFileListNative JavaScript Array
Core PropertyOnly length (number of files).length (number of elements), plus inherited properties like prototype, constructor, etc.
Index AccessSupports fileList[index] (e.g., fileList[0]).Supports array[index] (e.g., arr[0]).
InheritanceInherits from Object.prototype.Inherits from Array.prototype, which includes array-specific methods.

Methods#

FileList has very few methods compared to arrays:

  • item(index): Returns the File object at the specified index (equivalent to fileList[index]).
    Example: fileList.item(0) is the same as fileList[0].

In contrast, native arrays inherit dozens of methods from Array.prototype, such as:

  • Modification: push(), pop(), splice(), sort().
  • Iteration/Transformation: map(), filter(), forEach(), reduce().
  • Utility: includes(), find(), some(), every().

The "Array-like" Distinction#

FileList is often called "array-like" because it has:

  • A length property.
  • Indexed access to elements (fileList[0], fileList[1], etc.).

However, it lacks the prototype chain of a native array. Since FileList inherits from Object.prototype (not Array.prototype), it cannot access array methods directly.

Why Isn’t FileList an Array?#

The decision to make FileList array-like but not a true array stems from several key factors:

Historical Context: DOM APIs and Early JavaScript#

The FileList interface was standardized in the early 2000s (as part of the File API), a time when JavaScript arrays were far less powerful than they are today. Early JavaScript (ES3 and earlier) lacked features like Array.prototype.forEach(), map(), or the spread operator. DOM APIs of the era (e.g., NodeList, HTMLCollection) were designed as simple, lightweight collections with minimal methods—closer to objects than modern arrays.

Updating FileList to inherit from Array.prototype would break backward compatibility with code written for these older interfaces.

Immutability: Reflecting User Intent, Not Programmatic Changes#

FileList is immutable: its contents cannot be modified programmatically. The only way to change a FileList is through user action (e.g., selecting new files via the input element). This design ensures the FileList always reflects the user’s actual selection, not arbitrary changes by scripts.

If FileList were an array, developers might try to modify it directly (e.g., fileList.push(newFile)), which would decouple the FileList from the user’s intended selection.

Security: Protecting User-Selected Files#

User-selected files are a sensitive security boundary. Allowing scripts to modify FileList could enable malicious actors to:

  • Add fake files to the list (e.g., spoofing a virus as a harmless document).
  • Remove files the user intended to upload.
  • Tamper with file metadata (e.g., changing a file’s type to bypass validation).

By making FileList read-only and non-modifiable, browsers prevent such tampering.

Consistency with Other DOM Collections#

FileList follows the pattern of other DOM collections like NodeList (for DOM nodes) and HTMLCollection (for HTML elements). These collections are also array-like but not arrays, with similar immutability and limited methods. This consistency simplifies learning and usage across DOM APIs.

Working with FileList as if It Were an Array: Conversion Methods#

While FileList isn’t an array, you can convert it to an array to unlock array methods like map(), filter(), or forEach(). Here are the most common conversion techniques:

Using Array.from()#

Array.from() creates a new array from an array-like or iterable object. It works seamlessly with FileList:

const fileList = fileInput.files;
const filesArray = Array.from(fileList); // Converts FileList to array
 
console.log(filesArray instanceof Array); // true

Using the Spread Operator ([...fileList])#

The spread operator (...) "spreads" the elements of an iterable object into a new array. Since FileList is iterable in modern browsers, this works:

const fileList = fileInput.files;
const filesArray = [...fileList]; // Converts FileList to array

Using Array.prototype.slice.call()#

For older browsers (e.g., IE), Array.prototype.slice.call() can convert array-like objects to arrays:

const fileList = fileInput.files;
const filesArray = Array.prototype.slice.call(fileList); // Legacy conversion

Example: Applying Array Methods#

Once converted to an array, you can use array methods to process files. For example:

const fileList = fileInput.files;
const filesArray = Array.from(fileList);
 
// Filter files larger than 1MB (1,048,576 bytes)
const largeFiles = filesArray.filter(file => file.size > 1048576);
 
// Map to file names and sizes
const fileInfo = filesArray.map(file => ({
  name: file.name,
  sizeKB: Math.round(file.size / 1024)
}));
 
console.log('Large files:', largeFiles);
console.log('File info:', fileInfo);

Common Pitfalls to Avoid#

Directly Using Array Methods on FileList#

Attempting to call array methods like map() or filter() directly on FileList will fail, as FileList does not inherit from Array.prototype:

const fileList = fileInput.files;
fileList.map(file => file.name); // ❌ Error: fileList.map is not a function

Fix: Convert FileList to an array first (see above methods).

Attempting to Modify FileList#

Since FileList is immutable, trying to modify it (e.g., adding/removing files) will throw an error:

const fileList = fileInput.files;
fileList.push(new File(['fake content'], 'malicious.txt')); // ❌ Error: fileList.push is not a function
fileList[0] = new File([''], 'replaced.txt'); // ❌ Fails silently (no error, but no change)

Fix: To "modify" the list, prompt the user to select new files via the input element.

Assuming Universal Iterability#

While modern browsers (Chrome 51+, Firefox 50+, Edge 12+) treat FileList as iterable (supporting for...of loops), older browsers (e.g., IE) do not. For example:

// Works in modern browsers but fails in IE
for (const file of fileList) {
  console.log(file.name);
}

Fix: Convert to an array first for cross-browser compatibility.

Conclusion#

FileList is an array-like DOM object designed to safely and accurately represent user-selected files. It is not a native JavaScript array due to historical API design, immutability requirements, security concerns, and consistency with other DOM collections. While its limited properties and methods can feel restrictive, converting FileList to an array (via Array.from(), the spread operator, or slice.call()) unlocks the full power of array methods.

By understanding FileList’s design and limitations, you can work with user files more effectively and avoid common pitfalls.

References#