質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

91.04%

  • JavaScript

    13767questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

input type="file" multiple でuploadする度に変数をカウントアップさせる

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 231

pegy

score 54

複数のファイルをアップロードすることを許可しているのですが、アップロードされている
ファイルをタイムリーにカウントしようとしております。
そこで、アップロードされる度にそのファイル個数(files.length)を変数に加算するために
file_length+=element.files.length;
としているのですが、NaNが返ってきてしまいます。
+=の加算代入演算子の使い方が誤っているのでしょうか?
よろしくお願いいたします。

<input type="file" id="files" style="display: none" value="2097152" name="file" multiple />
<script type="text/javascript">
            var element=document.getElementById('files');
            var file_length;
            $(function(){
                $('#files').on('change',function(){
                    file_length+=element.files.length;
                    console.log(file_length);
                })

            });
        </script>


[加筆]
ローカルスコープからグローバルスコープの変数に加算代入演算したいということになりますが、
そもそも不可能なのでしょうか? スコープの問題もありますが、なぜNaNが返ってくるのかわかりません。。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+3

変数宣言時にfile_lengthに値を代入していないからではないでしょうか?

var file_length = 0;とするべきです。

[加筆]に対し追記:

javascriptの場合、外側で宣言した変数は特に何も気にすることなくグローバル変数として使用できたはずです。

追記:

繰り返しになりますがpythonじゃあるまいし(pythonの場合はglobalの明示が必要)ローカルスコープでグローバル変数が使えないなんて事は無いですよ?

サンプル

もしずっと0なのでしたら、そもそもelement.files.lengthの値が0だったりしませんか?

ちなみに実行タイミング的にconsole.log(file_length);//ここのグローバル変数を加算していきたい!における出力は0が正しいです。

さらに追記:

ローカルで変化した変数をグローバルで参照したい

とのことですが、今回の処理の場合は全部グローバル変数で管理する方がいいと思いますよ?

関数内でvarを使ってローカル変数を宣言された場合、関数を抜けた段階で値がリセットされてしまいますから、そもそもローカル変数に値を保存するということ自体がまず不可能です。

var glbl;

var lcl = function(n){
  var val = 0;
 // ↑ここで0を代入してしまっている時点で、、あっ、ふ〜ん(察し)という感じですが(^ ^;
 // しかし入れないわけには行きません。
  val += n;
  console.log(val);

  glbl = val; // 質問者様が行いたいと考えておられること
}

lcl(10); // 期待する値 : 10 実際 : 10
console.log(glbl); // 期待する値 : 10 実際 : 10
lcl(10); // 期待する値 : 20 実際 : 10
console.log(glbl); // 期待する値 : 20 実際 : 10
lcl(10); // 期待する値 : 30 実際 : 10
console.log(glbl); // 期待する値 : 30 実際 : 10

ですから関数内でもグローバル変数のみを用いる、という方法のままでいいと思います。

その直後(グローバル変数に保存した直後)にelement.files.lengthで得られた値を使って別な処理をしたいわけでも無い限り、使い捨てのローカル変数を用意するだけ無駄です。

どうしてもスコープを意識したいのであればオブジェクト指向の考え方を使い、インスタンスのプロパティに保存すれば意図した動作となるとは思いますが、今回の動作でそのような大掛かりなものは不要だと思われます。

<button>btn</button> step : <input type="number" value="10" />
<script>
$(function(){
  var glbl = 5;

  var lcl = new (function(){
    this.step = 10;
    this.add = function(){
      glbl += this.step;
      alert(glbl);
    };
  })();

  $("button").click(function(){lcl.add();});
  $("input").on("change",function(e){
    lcl.step = parseInt(e.target.value);
  });
});
</script>

サンプル

上記サンプルでは足していく値(step)をオブジェクト内に保存しています。

私の方こそ質問をよく理解していないかもしれません。。もし欲しい答えでなければすみません。。m(_ _)m

ようやく質問者様のおっしゃりたいことがわかってきたような気がするので改めて追記させてください。

当然グローバルでは加算されていないため、0が出力されてしまいます。

違います。ローカルスコープにおいてすでに参照されている変数はグローバル変数ですから、changeイベントが行われたあとにはちゃんとグローバル変数であるfile_lengthに新しい値が代入されています。

しかしながらconsole.log(file_length);//ここのグローバル変数を加算していきたい!はそもそもchangeイベントが行われた後には実行されません

このコードが実行されるのはchangeイベントのリスナーをinput要素に付与した直後のみですから、0が出力されるんです。先ほど「ちなみに」として発言したのはこれをさしてのことです。

決してグローバル変数の値が更新されないから0が出力されるのではありません。

むしろ//console.log(file_length); ここじゃない!が正しい変更後の値を示す場所です。ここで出力される値はグローバル変数のものです。ローカル変数ではありません。

証拠としてもう一つサンプルを挙げようと思います。

<input type="text" /> <button>hogeの中身</button>
<script>
var hoge = '';

$(function(){
  $('input').on('change',function(e){
    hoge = e.target.value;
    console.log('ここじゃない!の場所 : ' + hoge);
  })
  console.log('ここのグローバル変数を加算していきたい!の場所 : ' + hoge);
});

$(function(){
  $('button').click(function(){
    console.log('ちゃんとグローバルに保存されている : ' + hoge);
  });
});
</script>


サンプル

サンプルを試していただければわかると思いますがconsole.log(file_length);//ここのグローバル変数を加算していきたい!に当たる場所は最初に一回実行されているだけです。

追記のために非常に長くなってしまいました。。すみません。。

不明点等あればまた返信ください。m(_ _)m

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/10 19:53 編集

    早速コメントありがとうございます。
    初期値は勝手に0とJavascriptが判断してくれると誤解しておりました。
    undefined+number=NaNということでしょうか。
    本件はおかげ様で理解することができたのですが、
    スコープの問題として、ローカルスコープでグローバルスコープの変数に加算代入演算したい場合も
    あるかと想像しているのですがその様なことも可能なのでしょうか?
    下記の様な方法です。当然グローバルでは加算されていないため、0が出力されてしまいます。
    重ねてで誠に申し訳ございませんが、ご教示いただけましたら幸いです。

    <script type="text/javascript">
    var element=document.getElementById('files');
    var file_length = 0;
    $(function(){
    $('#files').on('change',function(){
    file_length+=element.files.length;
    //console.log(file_length); ここじゃない!
    })
    console.log(file_length);//ここのグローバル変数を加算していきたい!

    });
    </script>

    キャンセル

  • 2017/10/10 20:07

    追記しました。よろしくお願いします。m(_ _)m

    キャンセル

  • 2017/10/10 20:15

    初心者の私にお付き合いをいただき申し訳ございません。。そしてありがとうございます。

    >ローカルスコープでグローバル変数が使えないなんて事は無いですよ
    これはローカルスコープからグローバルスコープの変数を参照することができるということかと理解しております。ご作成いただいたサンプルもグローバルの10を参照してローカル上で5を加算しているという意図でご用意いただいたのかと思います。

    質問の意図としては反対でローカルで変化した変数をグローバルで参照したいということです。

    >console.log(file_length);//ここのグローバル変数を加算していきたい!における出力は0が正しいです。
    まさにここの部分なのですが、グローバルスコープ上の変数でもファイル数のカウントアップの状態を管理したく、0ではなくカウントアップした数が代入されてほしいということになります。

    意図をうまく伝えることができずに申し訳ございません。。

    キャンセル

  • 2017/10/10 22:04

    追記しました。よろしくお願いします。m(_ _)m

    キャンセル

  • 2017/10/11 00:40

    さらにまた追記しましたので、よろしくお願いします。m(_ _)m

    キャンセル

  • 2017/10/11 10:14

    namnium1125様
    詳細なサンプルまで有難うございます!大粒涙付きの感謝です。。。

    最後のサンプルでいうところの
    print('ここのグローバル変数を加算していきたい!の場所 : ' + hoge);
    という箇所が「イベントが行われた後には実行されません。」ということなのでしょう。
    これが実行される時点ではhogeには何も格納されていないため、
    「ここのグローバル変数を加算していきたい!の場所 : '」が1度しか表示されないことが
    仰りたい意味かと理解しました。
    changeイベントやclickイベントの外なので、当然といえば当然なのかもしれませんが。。。

    一度グローバルスコープで宣言し、ローカルスコープから参照した変数についてはローカル内での処理で影響を与えることができるのですね。。誤解をしておりました。
    少し内容を変えて
    hoge+=(e.target.value)|0;
    としてみましたが、グローバル変数hogeに影響を与えていることを確認しました。
    https://jsfiddle.net/mcLsarpy/2/

    ただ、なぜか加算代入演算子中では|0をしてもNumber()でも文字列から変わらずに
    連結されてしまいます。。。

    キャンセル

  • 2017/10/11 13:51

    ?ビット論理和を出してどうするのでしょうか??ごめんなさい私の方が無知なのかも…

    もし3項演算子のつもりでしたら、
    javascriptの3項演算子は`変数 = 条件 ? trueの時 : falseの時;`です。

    こういうことがしたかったのでしょうか?
    https://jsfiddle.net/mcLsarpy/5/

    キャンセル

  • 2017/10/11 15:40 編集

    コメント有難うございます!
    結果としてやりたかったことはまさに提示頂いたとおりなのですが、だ
    加算代入演算(a+=c ⇒a=a+c)を使えば、
    element.files.length;でファイル数を取得するたびにグローバル変数file_lengthに数値が加算されるかと
    想像したのですが、(つまりアップロードされたファイル数をカウントできる。multipleなので1ずつ加算はできないので)
    つまりa =file_length で c=element.files.length;ですね。|0は数値型への変換です。
    ご提供の3項演算子と同じ結果が得られると思ったのですが、加算代入演算子を使用するとどうしても文字列になってしまいます。
    すみません、もとの質問の趣旨からはかなりそれてしまいますが。
    基本的な部分は殆ど解決したのでnamnium1125先生に心から感謝です!

    キャンセル

  • 2017/10/12 00:35 編集

    あぁ、、原因判明しました。`var hoge = ''`ではなく`var hoge = 0`にしてください。解決するはずです。最初に気づかなくてすみません。。(^ ^;

    https://jsfiddle.net/namnium1125/mcLsarpy/6/

    キャンセル

  • 2017/10/12 00:32

    すみません、こちらこそ凡ミスで申し訳ございません。
    今回の質問で初心者ながら、1レベルアップしたと思っています。
    回答者様に本当に深謝でございます。
    また、こんな有意義な場を提供してくれる、teratailは素晴らしい!
    改めて有難うございました。

    キャンセル

+2

formdataでテスト

$(function(){
  var file_length = 0;
  $('input[type=file]').on('change',function(){
    if($(this).closest("form").length==0){
      $(this).wrap("<form>");
    }
    var fd=new FormData($(this).closest("form").get(0));
    file_length+=fd.getAll($(this).attr("name")).length;
    console.log(file_length);
  });
});
<input type="file" name="f1" multiple />
<input type="file" name="f2" multiple />
<input type="file" name="f3" multiple />

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/11 17:47

    コメント有難うございます。
    カウント加算させるための違うアプローチとしてコードを勉強させて頂きます。

    キャンセル

  • 2017/10/11 17:58

    挙動が想定と合致しているかだけ確認しておいて下さい。
    FormDataはフォーム系処理をする場合あらゆる場面で使用されるものなので
    覚えておいて損はないでしょう

    キャンセル

  • 2017/10/12 00:36

    フォーム関連の処理でformDataオブジェクトは使ったことがなかったです。早速学びに取り掛かります。貴重な情報を提供頂き、有難うございます

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 91.04%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • JavaScript

    13767questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。