03 July 2010

jsのループまとめ

わざわざブログに書くほどのことでもないんですが, 最近全然書けてなかったので. あとamachangさんのエントリを読んでもらえれば解決してしまう話です.

for と for ... in

一般的なjsではforを使った制御構文が2種類あります. ひとつは一般的なfor. cなどとほぼ同じものです.

var a = [1, 2, 3];
for (var i=0; i[i]);

説明の必要はないですね.

もうひとつ, for ... in という構文があります. あるオブジェクトのプロパティ名についてループします.

var a = [1, 2, 3];
for (var i in a)
    console.log(a[i]);

注意が必要なのは, for ... in はオブジェクトの"プロパティ"に対してループしているという点です. もし配列オブジェクトのプロトタイプが拡張されていたら, それもループの対象となってしまいます. よって for ... in は配列のループには使うべきではありません. あくまでオブジェクトのプロパティを走査したい場合にだけ使うべきです.

Array.prototype.foo = 123;
var a = [1, 2, 3];
for (var i in a)
    console.log(a[i]);  // 1, 2, 3, 123 などと表示される

for each ... in

JavaScript 1.6 以降では for each ... in という構文を使うことができます. for ... in と似ているのですが, 違いはプロパティ名ではなくてプロパティそのものに対してループする点です.

var o = {"first": 1, "second": 2, "third": 3};
for each (var i in o)
    console.log(i);  // 1, 2, 3

こちらも for ... in と同様の理由で配列のループに使うべきではありません.

Array オブジェクトの反復メソッド

JavaScript1.6 以降 (一部1.8以降) では配列全体を操作する際に便利なメソッドがいくつか定義されています. それぞれのメソッドにマッチする用途であれば, 非常にスマートに書く事ができるようになります.

Array - JavaScript | MDN

こちらからいくつか抜粋します.

forEach は配列の各要素にあたえられたコールバック関数を適用します.

[1, 2, 3].forEach(function(i) {console.log(i)});

map は配列の各要素にコールバックを適用し, 新たな配列を作成します.

console.log([1, 2, 3].map(function(i) { return i*i;}));  // [1, 4, 9]

// javascript 1.8 以降の expression closures を使えばもっと簡潔に書けます
console.log([1, 2, 3].map(function(i) i*i));  // [1, 4, 9]

mapがあるならということでreduceも存在します. が, こちらは JavaScript 1.8 以降なので注意してください.

console.log([1, 2, 3].reduce(function(a, b) a + b));  // 6

このほかにも配列の要素をテストするeveryやsome, 配列をフィルタするfilterなどもあります.