LoginSignup
9
6

More than 5 years have passed since last update.

FileListをArrayのように扱う

Last updated at Posted at 2016-03-15

最近FileAPIを使うことがあり、
FileListってArrayと似たようなもんやろ!!!!!」forEachッターン!!!)
ってやったら見事に動かなかったので拡張した話を書きます。

そもそもFileListってなにができんの

MDNを見ると。
https://developer.mozilla.org/ja/docs/Web/API/FileList

この型のオブジェクトは、 <input> 要素の files プロパティによって返されます;これによって、 <input type="file"> 要素で選択されたファイルのリストにアクセスできます。

ここだけ読むと完全に「Array継承してんじゃねこれ?」って感じがある。
読み進めると。

スクリーンショット 2016-03-15 22.08.03.png

メソッドが一つしかない。
なんでや。
ブラウザのコンソールで確認。
スクリーンショット 2016-03-15 22.09.47.png
スクリーンショット 2016-03-15 22.09.21.png

なんでや!
forで回すのなんて嫌や!!
いろいろ拡張してやる!!

拡張する

単純にprototypeに追加していけばいい感じになるはず。

FileList.prototype.reduce = function(fun, initialValue){
  var result = initialValue;
  for(i = 0; i < this.length; i++){
    result = fun(result, this[i]);
  }
  return result;
}

たぶんこんな感じ。
ですが、Arrayreduceが実装されてんだし、自分でわざわざ実装しなくてもいい気がするんだよなー。と僕は思いました。
なので、

FileList.prototype.reduce = function(){
  return Array.prototype.reduce.call(this, ...arguments)
}

こうした。
ブラウザによっては動かないかもしれないが、Chromeでは動いた。

ほかのmap等も同じようにやってけば
FileListArrayのメソッドを使えるようになると思う。
pushとかは無理だと思う。

現場からは以上です。

追記

@think49 さんにコメントを頂きました!
http://qiita.com/merotan/items/1b94ba43c26a6c370661#comment-11fe5cf1b1d81087e017

未検証ですが、Array.prototype.reduce の仕様を読む限りでは「故意に汎用的に」定義されているように見えますので下記コードでいい気がします。
22.1.3.18 Array.prototype.reduce ( callbackfn [ , initialValue ] ) – ECMA-262 6th Edition

FileList.prototype.reduce = Array.prototype.reduce;

ただし、上記方法及び本記事で紹介されている方法はいわゆるprototype汚染を誘発するので Object.defineProperty で {enumerable: false} を指定するとベターです。

Object.definePropertyでやってみた。

Object.defineProperty(FileList.prototype, 'reduce', {
  value: Array.prototype.reduce,
  enumerable: false
});

こうすると良さそう。

9
6
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
6