連載
» 2014年11月14日 18時43分 公開

TypeScriptで学ぶJavaScript入門:第7回 繰り返し処理(2):for/for ... in文 (3/3)

[羽山博,著]
前のページへ 1|2|3       

for ... in文

 では、次にfor ... in文を見てみよう。for ... in文はオブジェクトのプロパティ名を1つずつ取り出して順に処理していく。そして、取り出すプロパティ名がなくなると繰り返しの終了となる。こちらも簡単な例から見ていこう。オブジェクトに関してはまだ何も学んでいないが、繰り返し処理の書き方と働きは分かるはずなので、心配せずに読み進めていってほしい。

 以下の例は、モンスターの名前、HP(生命力)、MP(魔力)を表示するプログラムである。

class Monster { // (1)
  name: string;
  hp: number;
  mp: number;
}
var m: Monster = new Monster(); // (2)
m.name = "Dragon";
m.mp = 100;
m.mp = 200;
document.body.innerHTML = "モンスターのステータス一覧<br/>";
for (var x in m) {
  document.body.innerHTML += x + ":" + m[x] + "<br/>"// (3)
}



 (1)ではクラスを定義している。(2)ではクラスからオブジェクトを作成し、変数mで参照できるようにしている。これらのコードの書き方は回を改めて説明するが、以下のような図のイメージで働きを捉えておくといい。

クラスの定義とオブジェクトの作成 クラスの定義とオブジェクトの作成

 若干の語弊はあるが、クラスとはある機能を持った部品の設計図のようなもので、その設計図から作られた実際の部品がオブジェクトに当たる。クラスにはその性質を表すプロパティと、動きを表すメソッドがある。

 といった一般的な説明はさておき、要するに、変数mで参照されるオブジェクトにはname、hp、mpという3つのプロパティがあるということだ。(3)では、for ... in文で順に取り出されたプロパティ名(変数xに代入されている)を表示する。つまり、最初は変数xに“name”が代入され(3)の文が実行される。次は変数xに“hp”が代入され(3)の文が実行される。続いて、変数xに“mp”が代入され(3)の文が実行される。そして、それ以上プロパティがないので、繰り返しを抜ける。

 なお、(3)ではオブジェクト名[プロパティ名を表す文字列]という書き方で、プロパティの値も取り出し、併せて表示している。実行例は以下の通り。

図8 for ... in文を使ってプロパティ名とプロパティの値を全て表示する 図8 for ... in文を使ってプロパティ名とプロパティの値を全て表示する

 では、for ... in文の書き方を確認しておこう。for文の場合と同様、形式1と形式2の違いは、文が単一の文であるか複合文にしているかだけなので、実質的に同じことを表している。

図9 for ... in文の構造を確認する 図9 for ... in文の構造を確認する

 for ... in文の働きは、オブジェクトのプロパティ名を1つずつ取り出して順に処理していくことであると述べたが、実際にはプロパティ名だけでなくメソッド名も取り出される。が、ここではこれ以上深入りしないことにしよう。

for ... in文は配列に対して使うのは避ける

 最後に、for ... in文の使い方に関する留意事項について触れておこう。for ... in文を使えば、配列の全ての要素を処理することもできる。記述が簡略になるので、for文の代わりにfor ... in文を使いたくなるが、配列に対してfor ... in文を使うのは避けた方がいい。

 配列についても、まだ本連載では取り扱っていないが、実例を見ればだいたい意味が分かるだろう。以下の例は、配列の隣り合う要素を足し合わせて、その結果を表示するプログラムである。かなり強引ではあるが、for ... in文を使って書いてみたものだ。しかし、残念ながら期待した結果は得られない。

var data: number[] = [10, 20, 30, 40, 50];
var sum: number;
for (var i in data) {
  if (i >= data.length - 1) break;      // (1)
  sum = data[i] + data[i + 1];  // (2)
  document.body.innerHTML += sum + "<br/>";
}



 dataという名前の配列には5つの要素がある。配列の要素は0から始まるインデックスを[]の中に書いて指定する。

 繰り返し処理の中では、(2)で0番目の要素と1番目の要素を足し合わせ、次に1番目の要素と2番目の要素を足し合わせ...という順に処理が進められる。(1)では、最後から1つ手前までの要素を処理するために、最後の要素にたどり着いたら繰り返しを抜けている。……というつもりのコードなのだが、(2)の部分が正しく動かないので、結果は以下のようになってしまう。

図10 隣り合う要素を足し合わせるプログラムの実行結果。期待通りに動かなかった 図10 隣り合う要素を足し合わせるプログラムの実行結果。期待通りに動かなかった

 期待通りに動かなかった理由は、for ... in文の場合、変数に代入されるオブジェクトのプロパティ名は文字列であるということだ。配列の場合はインデックスが代入されるのだが、やはり文字列として代入される。従って、最初は変数iに0ではなく"0"が代入される。最初の繰り返しでは、(2)は以下のようになる。

sum += data["0"] + data["0" + 1];


最初の繰り返しにおける合計値の計算

 そのため、配列のインデックスは以下のように計算される。

sum += data["0"] + data["01"];


「文字列」と「数値」の加算結果は文字列になる

 data["0"]はdata[0]と見なされるが、data["01"]はdata[1]とは見なされない。存在しないデータを利用しようとしているので、NaNという結果が表示されたというわけだ。それ以降も同様である。

 そういうわけで、配列の処理には素直にfor文を使った方がいい。正しく動くプログラムと実行結果は以下の通りだ。

var data: number[] = [10, 20, 30, 40, 50];
var sum: number;
for (var i = 0; i < data.length - 1; i++) {
  sum = data[i] + data[i + 1];
  document.body.innerHTML += sum + "<br/>";
}



図11 隣り合う要素を足し合わせるプログラムの実行結果 図11 隣り合う要素を足し合わせるプログラムの実行結果

[コラム]for each ... in文

 JavaScript 1.6以降では、オブジェクトのプロパティの値を取り出すfor each ... in文が使えます。for ... in文ではプロパティの名前を取り出すのに対して、for each ... in文はプロパティの値を取り出すことに注意してください。ただし、for each ...in文はECMAScriptやTypeScriptでは使えません(当然のことながらエラーになります)。プロパティの値を取り出すには、サンプルプログラムで見たような方法を使ってください。



 今回はTypeScriptの繰り返し処理のうち、for文とfor ... in文を取り上げた。一定回数の繰り返しや、オブジェクトのプロパティ名を列挙するのに便利であるということが分かったと思う。

 次回は同じ目的の変数を数多く使うときに便利な配列について解説する。配列とfor文は相性のいい組み合わせなので、今回の話のおさらいも含めて詳しく解説する。

「TypeScriptで学ぶJavaScript入門」のインデックス

TypeScriptで学ぶJavaScript入門

前のページへ 1|2|3       

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。