今回は配列を操作するときに便利なメソッドをまとめます!
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です。
コールバック関数の第一引数に前回の結果、一番最初は初期値が入ります。