マッスル・メモリー

筋肉エンジニアのブログ

【js】配列を操作するメソッドまとめ

今回は配列を操作するときに便利なメソッドをまとめます!

forEach

let titles = ['このすば', 'リゼロ', '幼女戦記', 'オバロ']

titles.forEach((title) => {
  console.log(title);
});
// このすば
// リゼロ
// 幼女戦記
// オバロ
function showTitle(title) {
  console.log(title);
}

titles.forEach(showTitle);
// このすば
// リゼロ
// 幼女戦記
// オバロ

気をつけてもらいたいのが、匿名関数を置かずに名前付きの関数を定義して使用する場合に、

titles.forEach(showTitle());
// undefined is not a function

showTitle()とカッコを付けてしまうとエラーになるので注意です。

map

mapを使うと配列から新たな配列を作ることができます。

let titles = ['このすば', 'リゼロ', '幼女戦記', 'オバロ']

let secondSeasonTitles = titles.map((title) => {
  return `${title}2`
});

console.log(secondSeasonTitles);
// ["このすば2", "リゼロ2", "幼女戦記2", "オバロ2"]

mapの中でreturnを忘れないようにしましょう。

filter

filterを使うことで条件に合致したものを返せます。

let characters = [
  { name: 'スバル', gender: 'man' },
  { name: 'レム', gender: 'woman' },
  { name: 'ラム', gender: 'woman' },
  { name: 'ロズワール', gender: 'man' },
];

characters.filter((character) => {
  return character.gender === 'woman';
});
// 0: {name: "レム", gender: "woman"}
// 1: {name: "ラム", gender: "woman"}

もちろん、forEachで記述することも可能ですが、可読性を考えるとforEachを使わない方が、読み手にわかりやすいです。

find

findでは条件に合った最初の要素を返します。

let characters = [
  { name: 'トン' },
  { name: 'チン', id: 1 },
  { name: 'カン' },
  { name: 'チン', id: 2 },
];

characters.find((character) => {
  return character.name === 'チン';
});
// {name: "チン", id: 1}

every, some

everyは全て条件を満たす場合trueを返します。

someはどれかが条件を満たす場合trueを返します。

// 説明
// パワーリフターがsq, bp, dlの合計がjcpStandardRecordという標準記録を超えているかどうか
// 超えるとjcpという大会に出場できる

let powerLifters = [
  { id:1, sq: 200, bp: 140, dl: 230 },
  { id:2, sq: 180, bp: 120, dl: 200 },
  { id:3, sq: 200, bp: 130, dl: 200 },
];

const jcpStandardRecord = 510;

let allParticipantsFlag ; // 全員出場できる
let someParticipantsFlag ; // 誰かは出場できる

allParticipantsFlag = powerLifters.every((powerLifter) => {
  return jcpStandardRecord <= (powerLifter.sq + powerLifter.bp + powerLifter.dl)
});

someParticipantsFlag = powerLifters.some((powerLifter) => {
  return jcpStandardRecord <= (powerLifter.sq + powerLifter.bp + powerLifter.dl)
});

console.log(allParticipantsFlag);
// false

console.log(someParticipantsFlag);
// true

someとincludesの使い分け

someとincludesどちらも、特定の要素が含まれているかをtrue/falseで判定しますが、どう使い分けたらいいのでしょうか?

配列の場合、

const animes = [  'このすば', 'リゼロ', '幼女戦記', 'オバロ']
let targetAnime = 'リゼロ';

animes.some((anime) => {
  return anime
} );
// true

animes.includes(targetAnime);
// true

どちらもtrueを返します。

しかし、オブジェクトの配列の場合は、

const animes = [
  { title: 'このすば', mainCharacter: 'カズマ' },
  { title: 'リゼロ', mainCharacter: 'スバル' },
  { title: '幼女戦記', mainCharacter: 'ターニャ ' },
  { title: 'オバロ', mainCharacter: 'アインズ' }
];

let targetAnime = {
  title: 'リゼロ',
  mainCharacter: 'スバル'
}

animes.some((anime) => {
  return anime === targetAnime;
} );
// false

animes.includes(targetAnime);
//false

どちらもfalseを返します。

実はオブジェクトを比較するときにその比較は同じ参照を指しているかどうかでテストされるのです。

const animes = [
  { title: 'このすば', mainCharacter: 'カズマ' },
  { title: 'リゼロ', mainCharacter: 'スバル' },
  { title: '幼女戦記', mainCharacter: 'ターニャ ' },
  { title: 'オバロ', mainCharacter: 'アインズ' }
];

let targetAnime = animes[1];

animes.includes(targetAnime);
// true

このようにすればincludesを使えますが、

基本的にオブジェクトを比較する場合はsomeを用いて

const animes = [
  { title: 'このすば', mainCharacter: 'カズマ' },
  { title: 'リゼロ', mainCharacter: 'スバル' },
  { title: '幼女戦記', mainCharacter: 'ターニャ ' },
  { title: 'オバロ', mainCharacter: 'アインズ' }
];

animes.some((anime) => {
  return anime.title === targetAnime.title && anime.mainCharacter === targetAnime.mainCharacter;
} );
// true

このようにします。

reduce

reduceは配列を左から右へ2つの値に対して、同時に関数を適用し単一の値にします。

(右から左へはreduceRightという関数があります。)

例えば、合計値を求めることができます。

let numbers = [1, 2, 3, 4, 5]

let sum = numbers.reduce((sum, number) => {
  return sum + number;
}, 0);

console.log(sum);
// 15

reduceでは、

配列.reduce(コールバック関数(前回の結果, 今回取り出した値), 初期値)

とします。

例でいうと初期値は0です。

コールバック関数の第一引数に前回の結果、一番最初は初期値が入ります。