Javascript配列の繰り返し基本操作はfor/forEach/some/map/filter

JavasScriptの配列の操作は基本ですが、初心者にとってはイマイチ慣れない部分があります。特に配列内の要素がオブジェクトの場合やネストが深いような場合、配列内の中の要素を取るのにちょっと手間取ってしまうケースがあったりします。

私も配列の操作で困った一人で、当初は

「ループと言えばfor文でしょ!」

と思っていたのですが、どうやらこれはイケてないようで、forEachやmapを使ったほうがどうやら良さそうだというところから入りました。

さらには配列の繰り返しにはほかにもいろいろあるということ、ローダッシュ等の配列操作系のJSライブラリを使ったほうが簡単に実現できる場合も多くあることも使っていくうちにわかってきました。

とはいえ、JavaScriptでそもそも用意されている関数を使って配列の繰り返し操作を覚えるのはやはり基本だと思います。

そこで今回は、JavaScriptの配列操作の基本、特に繰り返しや絞り込みの処理についてまとめてみました。基本的な配列操作を並べましたので、困ったときに自分用にも確認に使えそうです。

for文による配列の繰り返し

配列操作では繰り返し処理が基本となりますが、最初に配列の繰り返しで覚えるのがfor文です。

var array = [11, 22, 33, 44, 55];
for (var i = 0; i < array.length; i++) {
  console.log(array[i]);
}

上記のコードはarrayの要素を先頭からconsoleに出力しているだけですが、基本はこの方法で配列を先頭から繰り返し操作することができます。

//実行結果は次のようになる
11
22
33
44
55

配列操作においてIF文を使うのは、主に

  • 処理を途中で止める(break)
  • 処理をスキップする(continue)

の操作をしたい場合が多いかと思います。

breakによる処理の中止

IF文の繰り返し処理をある条件になったら止める(IF文を抜ける)ような場合、breakを使います。例えば繰り返しのインデックスが3になったらループを抜けたいような場合、次のようなコードで書くことができます。

var array = [11, 22, 33, 44, 55];
for (var i = 0; i < array.length; i++) {
  if (i === 3) break;
  console.log(array[i]);
}

結果は

11
22
33

となりますので、変数iが4になったらfor文を抜けているので、i>=4の場合のconsoleへの出力がされていないことが分かります。

continueで処理をスキップする

IF文の中である条件の場合は以降の処理をスキップして次の要素に進みたい場合は、continueを使います。

例えば次のようにコードを書いた場合、変数iが3以上の場合はfor文内の以降の処理がスキップされて先頭に戻ります。

var array = [11, 22, 33, 44, 55];
for (var i = 0; i < array.length; i++) {
  if (i >= 3) continue;
  console.log(array[i]);
}

そのため、結果は次のようになります。

11
22
33

上記コードの場合、breakの例と同じ結果となっています、動き的には異なっている点を押さえておく必要があります。

breakとcontinueの動きの違い

break:ループを抜ける

continue:次の要素の処理に進む

つまり、breakはIF文を抜けますが、continueはIF文を抜けません。配列の要素数が多いような場合で且つ、条件に該当したらループを抜けてもよいようなケースでは、breakを使うほうが良いでしょう。

.forEach()による配列の繰り返し

IF文は配列の繰り返しおいてはあまりイケてないようで、単純に全要素を繰り返すだけの場合はforEachを使ったほうがロジック的にもわかりやすくなります。こっちを使ったほうがモダンとか言われます(たぶん)。

例えば、先ほどの例をIF文からforEachに置き換えると次のようになります。

var array = [11, 22, 33, 44, 55];
array.forEach(function(str, i) {
  console.log(str);
});

IF文を使って配列の繰り返しを行っていた場合、この記載方式をパッと見ても混乱をきたしそうですね。ただ、慣れればとても簡単でIF文よりも使いたくなる書き方です。

forEachのカッコの中身は関数になっているのが分かるかと思いますが、第一引数に要素が、第二引数に繰り返しのインデックスが入っています。そのため、

console.log(str);

console.log(array[i]);

にしても結果としては同じになります(forEachでarray[i]のようには普通は使いません)。

forEachのメリットは、要素の変数への代入を勝手にやってくれる点だと個人的には思います。ここでは配列の要素の中身がstrという要素に入った状態で処理ができるので、コード量も少なくなるメリットもありますね。

配列内の要素がオブジェクトの場合にこそ使うことで、コードの可読性もあがります。

var array = [
 {code :11, name: 'name11'},
 {code :22, name: 'name22'},
 {code :33, name: 'name33'},
 {code :44, name: 'name44'},
 {code :55, name: 'name55'}
];
array.forEach(function(obj, i) {
  console.log(obj.code + ':' + obj.name);
});

このように、配列の要素がオブジェクトの場合、forEachでは直接「obj.code」のように参照できるので、わかりやすくなりました。

また、IF文で行っていたcontinueをforEachで実現したい場合、returnを使用します。

var array = [11, 22, 33, 44, 55];
array.forEach(function(str, i) {
  if ( i >= 3) return;
  console.log(str);
});

ただし、次の注意点がforEachではあります。

forEach利用時の注意

IF文で使用できていたbreakは使えません

繰り返しの途中でループを抜けることがforEachではできませんので、この点を押さえておきましょう。

.some()による配列の繰り返し

forEachのように配列を繰り返しで使いたいけれど途中でbreakしたいんだよな・・・

このような場合、someを使用します。

var array = [
 {code :11, name: 'name11'},
 {code :22, name: 'name22'},
 {code :33, name: 'name33'},
 {code :44, name: 'name44'},
 {code :55, name: 'name55'}
];
array.some(function(obj, i) {
  if (i === 3) return true;
  console.log(obj.code + ':' + obj.name);
});

使い方はこのように、forEachの部分をsomeに変更し、breakの部分をreturn trueとします。これでIF文+breakと同じ繰り返しのロジックを実現することができます。また、forEachと同様にcontinueの代わりにreturnを使うことで、処理をスキップさせることもできます。

someのポイント

途中でループを抜けたい(breakしたい)場合:return true;

途中で次の要素に進みたい(continue)したい場合:return;

returnの後にtrueを付けるか付けないかで動きが変わりますので、注意しましょう。

.map()による配列の繰り返し&絞り込み

forEachやsomeと同じような使い方ができる関数としてmapがあります。

先述のforEachの例について、forEachの部分をmapにしても同じような動作をします。

var array = [11, 22, 33, 44, 55];
array.map(function(str, i) {
  if ( i >= 3) return;
  console.log(str);
});

console.logの部分だけ見れば同じですが、forEachとmapでは次のような違いがあります。

forEachとmapの違い

forEach:戻り値なし

map:戻り値あり

戻り値があるかないかの違いだけですが、この違いによってmapはforEachより使える関数になっています。

例えば次のようなmapを使ったコードの場合、

var array = [
 {code :11, name: 'name11'},
 {code :22, name: 'name22'},
 {code :33, name: 'name33'},
 {code :44, name: 'name44'},
 {code :55, name: 'name55'}
];
var target = array.map(function(str, i) {
  return str.code;
});
console.log(target);

mapの戻り値を格納している変数targetの中身は、次のように配列データが入ります。

[11, 22, 33, 44, 55]

このように、mapを使うことで、対象の配列の中から特定のオブジェクトを抜き出すことができます。これはとても便利ですよね!

mapを利用する際の注意点としては、次の点がありますので、意識しておくとよいでしょう。

map利用時の注意点

mapの戻り値は配列

元の配列のすべての要素数分繰り返し処理がされる。

returnしたものが戻り値の配列に格納される。

returnしない場合、戻り値の配列にはundefinedが格納される。

特に注意が必要なのは、上記2番の「元の配列のすべての要素数分繰り返し処理がされる」という点です。forEachではIF文のcontinueと同じような動きをさせる場合はreturnをしていましたが、mapを利用する際はreturnだとundefinedが戻り値の配列に格納されますので、この点を忘れない異様にしておきましょう。

ただ、配列の中で特定の条件に一致したデータのみ別の配列を作りたいというケースがあるかと思いますが、その場合はfilterを利用します。

.filter()による配列の繰り返し&絞り込み

mapと似ているようで違う動きをするのがfilterです。fiterを使うことで、配列内で特定の条件に一致したもののみを抽出することができます。

fiterを使用して次のようなコードを実行した場合、

var array = [
 {code :11, name: 'name11'},
 {code :22, name: 'name22'},
 {code :33, name: 'name33'},
 {code :44, name: 'name44'},
 {code :55, name: 'name55'}
];
var target = array.filter(function(str, i) {
  if (i % 2 === 0) return true;
});
console.log(target);

filterの戻り値targetの配列の中身はこのようになります。

[
 {code :11, name: 'name11'},
 {code :33, name: 'name33'},
 {code :55, name: 'name55'}
];

このように、filterを使うことで、元の配列の中から条件に一致するデータを抜き出して別の配列を作ることができます。これもとても便利ですね。

mapの場合は元配列の中から特定のオブジェクトを返していますが、filterの場合はreturn trueになった元配列の対象インデックスの要素が返されます。

ちょっと間違いやすいので、改めてmapとfilterの違いを整理すると次のようになります。

mapfilter
戻り値の配列の要素数元配列と同じ条件に一致した数
戻り値の配列の中身map内でreturnしたオブジェクトfilter内でreturn tureしたインデックスの要素
returnしない場合の戻り値undefinedが格納される
(例)
[undefined,undefined,・・・]
戻り値に何も設定されない
(例)
[]

戻り値の配列を対象データのみにしたい場合はfilterを使うと良いでしょう。

IF文との違いはメソッドチェーンができること

filter時は注意

メソッドチェンができる

IF文ではなくforEachやmap、filterを使うメリットの一つが、メソッドチェーンを使えるということです。メソッドチェーンとは、戻り値に対してさらに処理を行うようなものです。

例えば次の例は、配列arrayの中で、codeが40未満のものを取得していますが、mapで取得した内容をさらにfilterで絞り込むことで実現しています。

var array = [
 {code :11, name: 'name11'},
 {code :22, name: 'name22'},
 {code :33, name: 'name33'},
 {code :44, name: 'name44'},
 {code :55, name: 'name55'}
];
var target = array.map(function(a, i) {
  return a.code;
}).filter(function(code) {
  return code < 40;
});
console.log(target);

メソッドチェーンを使うと感覚的にも処理が分かりやすくなっているかと思います。

ここでは紹介しませんが、Promiseではメソッドチェーンをよく使うので、この記述方法は押さえておくと役に立ちます。

まとめ

JavaScriptの配列操作の基本である、for、forEach、some、map、reduceについてご紹介しました。

配列操作はJavaScriptの基本なので、是非これらの関数についても押さえておきましょう。


コメントを残す

CAPTCHA


関連キーワード

Twitterでフォローしよう