複数のファイルをアップロードすることを許可しているのですが、アップロードされている
ファイルをタイムリーにカウントしようとしております。
そこで、アップロードされる度にそのファイル個数(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ページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
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
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+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 />
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.19%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2017/10/10 19:52 編集
初期値は勝手に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
2017/10/10 20:15
>ローカルスコープでグローバル変数が使えないなんて事は無いですよ
これはローカルスコープからグローバルスコープの変数を参照することができるということかと理解しております。ご作成いただいたサンプルもグローバルの10を参照してローカル上で5を加算しているという意図でご用意いただいたのかと思います。
質問の意図としては反対でローカルで変化した変数をグローバルで参照したいということです。
>console.log(file_length);//ここのグローバル変数を加算していきたい!における出力は0が正しいです。
まさにここの部分なのですが、グローバルスコープ上の変数でもファイル数のカウントアップの状態を管理したく、0ではなくカウントアップした数が代入されてほしいということになります。
意図をうまく伝えることができずに申し訳ございません。。
2017/10/10 22:04
2017/10/11 00:40
2017/10/11 10:14
詳細なサンプルまで有難うございます!大粒涙付きの感謝です。。。
最後のサンプルでいうところの
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:12 編集
結果としてやりたかったことはまさに提示頂いたとおりなのですが、だ
加算代入演算(a+=c ⇒a=a+c)を使えば、
element.files.length;でファイル数を取得するたびにグローバル変数file_lengthに数値が加算されるかと
想像したのですが、(つまりアップロードされたファイル数をカウントできる。multipleなので1ずつ加算はできないので)
つまりa =file_length で c=element.files.length;ですね。|0は数値型への変換です。
ご提供の3項演算子と同じ結果が得られると思ったのですが、加算代入演算子を使用するとどうしても文字列になってしまいます。
すみません、もとの質問の趣旨からはかなりそれてしまいますが。
基本的な部分は殆ど解決したのでnamnium1125先生に心から感謝です!
2017/10/11 22:23 編集
https://jsfiddle.net/namnium1125/mcLsarpy/6/
2017/10/12 00:32
今回の質問で初心者ながら、1レベルアップしたと思っています。
回答者様に本当に深謝でございます。
また、こんな有意義な場を提供してくれる、teratailは素晴らしい!
改めて有難うございました。