javascript 数列に3桁ごとカンマを入れる処理を例にした解説

web言語ロゴ

タイトルをどうするか迷ったのですが、本日は数列に3桁ごとカンマを入れる処理を例に使った、変数を空文字で宣言する理由メソッドの説明をして行きたいと思います。

例えば、シンプルに数列に3桁ごとにカンマ区切りを入れたいと思った場合

.toLocaleString()
.replace( /(\d)(?=(\d\d\d)+(?!\d))/g, ‘$1,’ )

などを利用すれば簡単にカンマ区切りを数列に入れるコトが出来るのですが、本日のメインは数列に3桁ごとカンマをいれるコト自体ではなく、その処理を例に使ったjavascriptの勉強といった初心者さん向けの内容となりますので、違った方法で進めていきたいと思います。

1.今回使用するコード

var num = "12345678";
var result = ""; //出力用変数の空文字宣言
for(var i = num.length-3; i>0; i-=3){
	result=","+num.substr(i,3)+result;
}
result = num.substr(0,i+3)+result;
console.log(result);

上記のコードを実行すると、コンソールの部分に以下の画像のように出力されます。

javascript コンソール画面

3桁ごとにカンマ区切りが入っています。

ちなみに、冒頭で述べた別のやり方

var num1 = (12345678).toLocaleString();
console.log(num1);

var num2 = String(12345678).replace( /(\d)(?=(\d\d\d)+(?!\d))/g, '$1,' );
console.log(num2);

でも同じ結果を得るコトが出来ます。

2.解説

var num = "12345678";
var result = ""; //出力用変数の空文字宣言
for(var i = num.length-3; i>0; i-=3){
	result=","+num.substr(i,3)+result;
}
result = num.substr(0,i+3)+result;
console.log(result);

では、1番最初に表示したコードを使いながら各部分の説明をしていきたいと思います。

var num = "12345678";

まずnumと言う変数に、文字列(string)として数字を入れています。
これは、この後カンマを入れる訳ですが、カンマは数値ではなく文字列なので、数字は文字列としておく必要がある為です。

var result = "";

次に出力用の変数を空文字で宣言します。
javascriptを始めたばかりの人だと、ここでつまづく人が多いと思います。
何故、何もないモノを宣言するのか?

空文字ではなく、ただの var result; と言う宣言だけではダメなのか?
空文字ではなく、同じfalseが返ってくる0ではダメなのか?
宣言と同時に代入出来るのだから、代入する時に初めて書けば良いのではないか?

このような疑問を持つ人もいると思いますが、どれをやってもダメです。
var result = “”; だからこそ上手く行きます。

詳しい説明は後でしていきます。

for(var i = num.length-3; i>0; i-=3)

次にあるのは上記のfor文、ループ処理です。

ここも後で説明しますが、簡単に説明すると、まず初期値の設定として、変数iにnum.length-3を入れています。
lengthと言うプロパティはこの場合、文字列の長さを取得するモノになります。

var num = "12345678";
     num = num.length;
console.log(num);

例えば上記の場合はコンソール欄に8を返します。
for文の中はそこから-3となっているので、とりあえず最初にiに入る数字は5になる訳です。

次が条件式で、 i>0 となっているので、変数iが0より大きい間は処理を繰り返すと言う意味になっています。

次に、増減式  i-=3 は繰り返す度に3ずつ引いてくださいという意味になります。

つまり、1回目の処理の時iは5でしたが、2回目の処理の時はiは2になり、3回目の処理の時には-1になり、条件式のiが0より大きい間繰り返すと言う条件から外れてしまうので、ループを抜けます。

result=","+num.substr(i,3)+result;

次に処理の内容ですが、まずsubstrと言うメソッドに関して説明します。

これは文字列を切り取る際に使うメソッドになります。
.substr(開始位置,切り取る長さ)となります。

var num = "12345678";
     num = num.substr(1,4);
console.log(num);

例えば、上記の場合はコンソール欄に2345を返します。
配列などもそうですが、最初を0番目として数えるので、今回の場合変な違和感があると思いますが、substr感覚の1番目とは変数numの2と言う数字になる訳です。

01234567 substrの番号付け
12345678 変数numに入ってる数字

よって、num.substr(1番目から,4つ切り取る)は コンソール欄に2345を返すのです。

result=","+num.substr(i,3)+result;

話しを上記の内容に戻します。

変数resultに、カンマと、変数numから(i,3)切り取った数字に、いままでのresultの結果を足して、代入する。
と言う形になっています。

まだよくわからない人もいると思いますので、また後で説明いたします。

result = num.substr(0,i+3)+result;

次にループの外にある上記コードは、変数resultへ、変数numから(0,i+3)切り取った数字に、いままでのresultを足して、代入する。
と言う形になっており、ここも後で話しますが、num.substr(0,i+3)は、for文のループの中で、変数numからまだ切り取れていない部分の数字を取得する命令になっています。

そして、最後のconsole.log(result);で、コンソール欄に12,345,678を出力している訳です。

また、混同しないようにここで確認ですが、for文の中や、最後の部分で「resultの結果を足して」「resultに足す」と言う表現をしていますが、今回の数字は数値ではなく、文字列として扱っているので、数式上の足し算ではありません。

var a = 3+5;
console.log(a); // 8

var b = "3"+"5";
console.log(b); // 35

上記 var bのように、文字列として足すと、計算ではなく、文字と文字の合体になります。
理解する上で、ここもかなり重要なので、混同しないようにしてください。

3.さらに細かい解説

では、なんとなく流れで説明してきましたが、さらに細かく見ていきたいと思います。

具体的に、各行の命令が上からどういった形で結果を出すまでに推移していくか、要所要所にconsole.logを入れて流れを見ていきたいと思います。

var num = "12345678";
var result = ""; //出力用変数の空文字宣言
console.log(result);
for(var i = num.length-3; i>0; i-=3){
	console.log(i);
	result=","+num.substr(i,3)+result;
	console.log(result);
}
console.log(i);
result = num.substr(0,i+3)+result;
console.log(result);

上記の命令をコンソール欄に出力させると、下記画像のように返ってきます。

javascript コンソール画面

コード内の要所要所にあるconsole.logにて出力されたモノです。
ちなみに画像内、1番右の数字は実際のコードの行番号になっています。

最初は3行目にあるconsole.log(result)の値を返している訳ですが、空文字なので、コンソール欄上では空白になっています。

既に何故、空文字ではないとダメなのかと理解されている方であれば問題ないのですが、まだ理解出来ていない場合は、最後に話した方がわかりやすいと思いますので、ここではまだ触れません。

では、コンソール欄の2行目、実際のコードでは5行目のconsole.log(i)に関してから話していきます。

これは、先程の話を覚えていれば、わかると思います。
for文の中で初期値として宣言した変数iには、まず5と言う数字が入った訳です。
※変数numの文字列の長さは8で、そこから3を引いた形です。

result=","+num.substr(i,3)+result;

次に上記の命令を経た、コンソール欄の3行目、実際のコードでは7行目のconsole.log(result)では「,678」を出力しています。

まず、substrメソッドによる処理から解説すると、この時点のiは5なので、num.substr(5,3)となります。
これを先程の番号表に当てはめてみると、

01234567 substrの番号付け
12345678 変数numに入ってる数字

substrの5番目から3つ切り取ると、変数numの678の3つが切り取られる訳です。
そして、文字列の「,」と切り取った「678」と、この段階ではまだ何も入っていない空文字状態のresultを文字列として足す形になります。

result=","+ "678" +" ";

と言うようなコトで、それが「,678」と出力された訳です。

javascript コンソール画面

次のコンソール欄を見ると「2」と出力されています。
コンソール欄の4行目ですが、実際のコードでは先程5と出力した5行目のconsole.log(i)です。
これはループの2回目の処理と言うコトです。

2回目の変数iは1回目の変数i = 5から3を引く形になるので、2になる訳です。

result=","+num.substr(i,3)+result;

次に2回目の上記命令で、コンソール欄の5行目、実際のコードでは再び7行目のconsole.log(result)で出力し、「,345,678」を出力しています。

これを再び、substrメソッドによる処理から解説すると、この時点のiは2なので、num.substr(2,3)となります。
これをまた番号表に当てはめてみると、

01234567 substrの番号付け
12345678 変数numに入ってる数字

変数numの345の部分が切り取られるのがわかると思います。
そして、文字列の「,」と切り取った「345」と、今度の「+result」には先程代入した「,678」が入っているので、それら3つを足すと、「,345,678」となる訳です。

result=","+ "345" +",678";

2回目のresultへの代入は、上記のようになると言うコトです。

javascript コンソール画面

次に、コンソール欄の6行目では「-1」と出力されています。
このconsole.logは、実際のコードでは9行目のfor文の外にあるconsole.log(i);です。

for文はiが0より下になると、ループを抜ける条件になっていましたので、ループは2回で止まっており、ループを抜けた時の変数iは「-1」になっていると言うコトです。
「8-3=5」、「5-3=2」、「2-3=-1」と言った変数iの流れです。

result = num.substr(0,i+3)+result;

そして、上記の命令を経た、コンソール欄の最後の行、実際のコードでは11行目のconsole.log(result)では「12,345,678」を出力しています。

細かい解説に入る前に、この部分に関しては「変数numからまだ切り取れていない部分の数字を取得する命令」になっているとお伝えした部分です。

今まで通り、まずsubstrメソッドによる処理から解説すると、この時点のiは−1なので、num.substr(0,-1+3)となります。
つまり、num.substr(0,2)になります。
これをまた番号表に当てはめてみると、

01234567 substrの番号付け
12345678 変数numに入ってる数字

となり、変数numの頭から2つ分、1と2が切り取られるのがわかると思います。
よって、

result = num.substr(0,i+3)+result;

は、

result = "12"+",345,678";

となり、最後のconsole.log(result)で「12,345,678」と出力された訳です。

では、次に空文字の宣言について話して行きたいと思います。

4.空文字で宣言する理由

例えば、どうせループ内で代入は行うし、ループ前には変数宣言だけしておく形にします。

var num = "12345678";
var result; //出力用変数の空文字宣言
console.log(result);
for(var i = num.length-3; i>0; i-=3){
	console.log(i);
	result=","+num.substr(i,3)+result;
	console.log(result);
}
console.log(i);
result = num.substr(0,i+3)+result;
console.log(result);

これを出力すると下記画像のようになります。

javascript コンソール画面

また同じような感じで、宣言自体ループ内で代入と同時にすれば良いのではと、ループ内で宣言と代入を同時にする形。

var num = "12345678";
for(var i = num.length-3; i>0; i-=3){
	console.log(i);
	var result=","+num.substr(i,3)+result;
	console.log(result);
}
console.log(i);
result = num.substr(0,i+3)+result;
console.log(result);

これを出力すると下記画像のようになります。

javascript コンソール画面

上記2つは同じような感じで、最初の例の方がわかりやすいかもしれませんが、javascriptの変数は宣言しただけの初期化してない段階では、「undefined」と未定義を表す値が入ってしまいます。
それが、for文内の命令

result=","+num.substr(i,3)+result;

の最後の部分で、まだ値が入っていないresultを足さないといけないので、undefinedが、ずっとついて回ってしまうのです。

これは、空文字と同じfalseを返す0を入れてもやはりダメで、

var num = "12345678";
var result = 0; //出力用変数の空文字宣言
console.log(result);
for(var i = num.length-3; i>0; i-=3){
	console.log(i);
	result=","+num.substr(i,3)+result;
	console.log(result);
}
console.log(i);
result = num.substr(0,i+3)+result;
console.log(result);

javascript コンソール画面

同じように0がついて回ってしまいます。

もちろんループの中での初期化宣言は、ループ処理で繰り返す度に初期化されてしまうのでダメです。

var num = "12345678";
for(var i = num.length-3; i>0; i-=3){
    var result = ""; //出力用変数の空文字宣言
    console.log(i);
    result=","+num.substr(i,3)+result;
    console.log(result);
}
console.log(i);
result = num.substr(0,i+3)+result;
console.log(result);

javascript コンソール画面

+resultをしても、先程述べたように、ループの度に変数resultは、初期化され空文字に戻ってしまうので、変数の中を足して増やしていくコトが出来ません。

このようなコトを避けるために、ループの外で、空文字で、宣言する必要があるのです。

ある程度、javascriptがわかる人であれば、当たり前にわかるコトでも、始めたばかりでこのような部分に当たると意味があるのかな?と疑問に思いやすかったりするものです。
気にせず、「まぁ必要なんだろ」と進める人は、進めながら振り返った時に、気付けたりもするのですが、1つずつ疑問に思ったコトは解決したい人だと、こういった部分でハマってしまうモノだったりします。

全てのケースで同じように使う訳ではありませんので、疑問に思った時は要所要所にconsole.logを差し込んで、結果を見ていくと悩みが意外と早く解決すると思います。

Categories: JavaScript