弥生研究所

人は誰しもが生きることの専門家である

【Javascript】繰り返し処理のまとめ

ECMAScript 5 で追加されたものを一覧化しました。

forEach()

for 文の場合:

// 要素の合計を求める
const array = [1, 2, 3, 4, 5];

let sum = 0;
for (let index = 0; index < array.length; index += 1) {
  sum += array[index];
}

console.log(sum);

forEach() で記述すると:

const array = [1, 2, 3, 4, 5];

let sum = 0;
array.forEach((element) => {
  sum += element;
});

console.log(sum);

Pros

  • 配列の要素だけに注目できる
  • for 分だとインデックスを正確に操作する必要があるが、forEach() なら確実に配列を巡回できる
  • 要素を与えられるので、配列にアクセスすることがなく、配列そのもの意図せずに壊すことがない
  • インデックスも使える(関数の引数は、配列要素の値、配列要素のインデックス、配列自身の 3 つが渡される)

Cons

  • for 文と違って途中で break できない

単純に配列を巡回させたいなら forEach() の方が良い。

map()

for 文の場合:

// それぞれの要素を2倍した配列を求める
const array = [1, 2, 3, 4, 5];

const array2x = [];
for (let index = 0; index < array.length; index += 1) {
  array2x[index] = array[index] * 2;
}

console.log(array2x);

map() で記述すると:

const array = [1, 2, 3, 4, 5];

const array2x = array.map(value => value * 2);

console.log(array2x);

Pros

  • 新しい配列を作成する処理ではなく、配列の要素を作成する処理に注目できる
  • インデックスも使える(関数の引数は forEach() と同じ)

Cons

  • 特になし

繰り返しの目的が、配列を元に新しい配列を作ることなら、map() の方が良い。

filter()

for 文の場合:

// インデックスが奇数の要素を求める
const array = ['a', 'b', 'c', 'd', 'e'];

const oddArray = [];
for (let index = 0; index < array.length; index += 1) {
  if (index % 2 !== 0) {
    oddArray.push(array[index]);
  }
}

console.log(oddArray);

filter() で記述すると:

const array = ['a', 'b', 'c', 'd', 'e'];

const oddArray = array.filter((value, index) => index % 2 !== 0);

console.log(oddArray);

Pros

  • 新しい配列を作成する処理ではなく、取得条件に注目できる
  • インデックスも使える(関数の引数は forEach() と同じ)

Cons

  • 特になし

繰り返しの目的が、配列から特定条件の要素を取得することなら、filter() の方が良い。

every(), some()

for 文の場合:

// 配列の要素が全て奇数か判定する
const array = [1, 2, 3, 4, 5];

let isAllOddNumber = true;
for (let index = 0; index < array.length; index += 1) {
  if (array[index] % 2 === 0) {
    isAllOddNumber = false;
  }
}

console.log(isAllOddNumber);

// 配列の要素に奇数が含まれているか判定する
let isSomeOddNumber = false;
for (let index = 0; index < array.length; index += 1) {
  if (array[index] % 2 !== 0) {
    isSomeOddNumber = true;
  }
}

console.log(isSomeOddNumber);

every(), some() で記述すると:

const array = [1, 2, 3, 4, 5];

const isAllOddNumber = array.every(value => value % 2 !== 0);

console.log(isAllOddNumber);

const isSomeOddNumber = array.some(value => value % 2 !== 0);

console.log(isSomeOddNumber);

Pros

  • 配列の操作ではなく、 判定条件に注目できる
  • インデックスも使える(関数の引数は forEach() と同じ)

Cons

  • 特になし

配列が空の場合は、every() は常に true、some は常に false を返す。 繰り返しの目的が、配列から特定条件の要素の存在を判定することなら、every(), some() の方が良い。

reduce(), reduceRight()

for 文の場合:

// 配列の要素から最大値を求める
const array = [1, 2, 3, 4, 5];

let max = 0;
for (let index = 0; index < array.length; index += 1) {
  if (array[index] > max) {
    max = array[index];
  }
}

console.log(max);

reduce() で記述すると:

const array = [1, 2, 3, 4, 5];

const max = array.reduce((result, value) => (value > result ? value : result), 0);

console.log(max);

reduce(), reduceRight() はちょっと難しい。 reduce には色々な意味があるが、「~を単純化する」「~をまとめる」という意味で理解すると機能を想像しやすいかもしれない。

例で言うところの result は各要素の繰り返し処理に引き継がれる値で、value は各要素の値になる。なお、省略しているが、3番目には配列の要素のインデックス、4番目には配列自身が引数として渡される。 reduce() の第2引数(例でいうと0)は、述語関数が一番最初に呼ばれるときの第1引数(例でいうと result)となる。reduceRight() は reduce() の逆順で処理するものである。

正直なところ微妙な感じ。forEach で十分なことが多そうなので、むしろむやみに多用しないほうが読みやすい印象がある。ほかのプログラマの事も考えて、慎重に採用したほうが良いだろう。

indexOf(), lastIndexOf()

for 文の場合:

// 配列から特定の値を持つ要素の一番最初のインデックスを求める
const array = [0, 1, 2, 1, 0];

const search = 1;
let result;
for (let index = 0; index < array.length; index += 1) {
  if (array[index] === search) {
    result = index;
    break;
  }
}

console.log(result);

indexOf() で記述すると:

const array = [0, 1, 2, 1, 0];

const max = array.indexOf(1);

console.log(max);

文字列操作でも同じ働きをするメソッドが用意されているので、説明不要かと思う。

f:id:yayoi-tech:20190616172928p:plain