こんにちは!2019年の10月にBRISKへ入社しました、以下のブログを書いているものです。
(よかったらのぞいてみてください!)
25歳・未経験からWebエンジニアになってみた【中途採用ブログ2019年10月~12月】
25歳・未経験からWebエンジニアになってみた【中途採用ブログ2020年1月~3月】
少し前にVue.jsを扱う案件に携わりました。
そこで、mapやsome,findなどのJavaScriptのループメソッドをはじめて扱いました。
ネットで調べてもしっくりくる記事がすくなかったので今回はそれらのメソッドについてまとめようと思います。
目次
この記事で登場する用語・記法
各メソッドの具体的な説明に入る前に、登場する用語や記法について軽く触れておきます。
var , let , const
var,let,constは変数を宣言する際に使うキーワードです。
let,constはES2015(ES6)から導入されました。
ES6とは、2015年に標準として策定されたJavaScriptの新しい文法です。
これらの主な違いは以下のようになります。
var | let | const | |
---|---|---|---|
初期値の省略 | OK | OK | NG |
再宣言 | OK | NG | NG |
再代入 | OK | OK | NG |
以下、上記表について具体的に見ていきます。
初期値の省略
constは初期値の省略ができません。
1 2 3 4 5 6 7 8 9 10 | var hoge1;//初期値省略OK console.log(hoge1);//undefined let foo1;//初期値省略OK console.log(foo1);//undefined const bar1;//初期値省略NG console.log(bar1);//エラー |
このように、constは定数(定まった値)として扱われるため、初期値がないとエラーになります。
再宣言
varは再宣言できますが、let,constはできません。
1 2 3 4 5 6 7 8 9 10 | var hoge1 = '初期値1'; var hoge1 = '初期値1';//再宣言OK let foo1 = '初期値1'; let foo1 = '初期値1';//再宣言NG const bar1 = '初期値1'; const bar1 = '初期値1';//再宣言NG |
再代入
var,letは再代入できますが、constはできません。
1 2 3 4 5 6 7 8 9 10 | var hoge1 = '初期値1'; hoge1 = '初期値2';//再代入OK let foo1 = '初期値1'; foo1 = '初期値2';//再代入OK const bar1 = '初期値1'; bar1 = '初期値2';//再代入NG |
以上が、var,let,constの説明です。
なお、こうした新しい記述は全ブラウザが対応しているのかが気になるところです。
varは基本的にどのブラウザでもOKですが、const,letはレガシーなブラウザ(例えばIE10)では使うことができません。
ただし、Babelなどのトランスパイラを使用すればconst,letを使ってもvarに置き換えてくれます。
よって、「トランスパイラが使えない」+「レガシーブラウザも対応しなければいけない」という状況であればvarを使い、そうでなければconst,letを使うのがよいでしょう
コールバック関数
コールバック関数は、他の関数に引数として渡す関数です。
「関数Aの処理が終わった後に、関数B(コールバック関数)を実行したい」などの目的で使用します。
言葉だとわかりずらいので例を見てみましょう。
1 2 3 4 5 6 7 | $('何らかの要素').on('click', function() { // .on()メソッドの中にあるfunctionがコールバック関数 //クリックが終わった後に実行される処理 }); |
上記の.on()メソッドの第二引数として渡されている関数がコールバック関数です。
この場合、「クリック」という処理が終わった後に、コールバック関数の処理内容が実行されます。
アロー関数
この記事ではアロー関数を使用していますので説明しておきます。
アロー関数は、ES2015(ES6)から利用可能になった新しいJavaScriptの構文の一つです。
アロー関数は以下の2つの理由から導入されました。
2.thisを束縛したくない
※特に2.が結構重要です。(アロー関数やthisの挙動に関しては今後記事にしたいと思います。)
アロー関数で書くと例えば上記のコードは以下のようになります。
1 2 3 4 5 6 7 8 9 10 11 | //従来の関数の書き方 var hoge = function() { //処理 } //アロー関数の書き方(ES6から登場) const hoge = () => { //処理 } |
アロー関数はとにかく省略がすごいです(語彙力…)
例を見てみましょう。
1 2 3 4 5 | var hoge = function(arg1) { return arg1; } |
上記のコードは、arg1という引数を受け取り、その引数を単純にreturnするhoge関数です。
これをアロー関数で書くと以下のようになります。
1 2 3 4 5 | const hoge = (arg1) => { return arg1; } |
さらに、関数に渡される引数が1つの場合、()を省略できます。
※引数がない場合は省略できません!!!
1 2 3 4 5 | const hoge = arg1 => { return arg1; } |
さらにさらに!
処理内容が1行の場合は、{}を省略できます。
また、文の返り値がそのまま返り値とみなされるのでreturnという文言すら要らなくなります。(すごい)
1 2 3 | const hoge = arg1 => arg1;//returnという文言すらいらない |
ここで、先ほどのコールバック関数で紹介したコードをアロー関数で書き換えると以下のようになります。
1 2 3 4 5 | $('何らかの要素').on('click', () => { // <-.on()メソッドの中にあるfunctionがコールバック関数 //処理 }); |
なお、アロー関数はInterner Explorer(IE)では対応していないので
IEまで対応させてコードを書きたい場合は、Babelなどのトランスパイラを使わないといけません。
テンプレートリテラル
テンプレートリテラルはES2015(ES6)から利用可能になった新しいJavaScriptの構文の一つです。
色々な機能があるのですが、ここではこの記事で扱っている記述についてのみ限定して解説します。
テンプレートリテラルでは以下のように記述することができます
1 2 3 4 5 6 | const age = 25; const str = `私の年齢は${age}歳です`; console.log(str);//私の年齢は25歳です |
ポイントはバッククォートと${ }です。
これを使うことで、今までプラス記号で文字を結合していたものがだいぶすっきり書けるようになりました。
従来の書き方↓
1 2 3 4 5 6 | var age = 25; var str = '私の年齢は' + age + '歳です'; console.log(str);// 私の年齢は25歳です |
配列
配列は各括弧[ ] の中に値が格納されている形のものを指します。
複数の要素を配列に格納したい場合は、カンマで区切ってあげます。
1 2 3 4 5 6 7 8 9 10 11 | var fruits = ['りんご', 'バナナ']; //.lengthで配列の長さを取得 console.log(fruits.length); // 2 //配列名[index番号]で値を取得 console.log(fruits[0]); // りんご |
オブジェクト
オブジェクトは波括弧{ } の中にキー(プロパティ)と値がセットになって格納されている形のものを指します。
複数の要素をオブジェクトに格納したい場合は、カンマで区切ってあげます。
1 2 3 4 5 6 7 8 9 10 | var fruits = {apple:'りんご', banana:'バナナ'}; //↓ドットによるプロパティへのアクセスで値を取得(ドット表記法) console.log(fruits.apple); // りんご //↓各括弧によるプロパティへのアクセスで値を取得(ブラケット表記法) console.log(fruits['apple']); // りんご |
注意事項
基本的な用語がわかったところですが、この記事を読むにあたり、いくつか意識してほしいことがあります。
意識してほしいこと1
この記事で紹介するループメソッドはオブジェクト型には使用できません。
(なんでだよー!!とか言わないでください。そういう仕様なのです。。。)
つまり、○○.map()とかの○○は配列でなければならないということです。
○○がオブジェクト型だと機能しません。
もし、オブジェクトに対してこれらの関数を使用したい場合はオブジェクトを配列に変換してあげないといけません。
やり方は以下の記事などを参考にするとよいでしょう。
ちょっとつまったjsでのobject⇒array変換
意識してほしいこと2
このあとループメソッドの紹介をしていくわけですが、ぜひ自分で同じコードを書きながら理解してほしいです。
でもいちいちエディタを立ち上げるのは面倒ですよね。
そんな方は以下のサイトを使いましょう!
エディタを立ち上げずとも簡単に実行結果を見ることができるのでオススメですよ♪
JS Bin
他にも類似のサービスはあるので色々と調べてみるのもよいですね
さて、それでは次からこの記事で扱うループメソッドを紹介していきます!!
forEach()
全ての要素に対してコールバック関数を一度ずつ実行します。
map や filter とは異なり新しい配列は生成しません。
使用例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | let sum = 0; const elms = [10, 20, 30, 40]; elms.forEach(elm => { // 配列の要素の合計を計算する sum += elm; }); console.log(sum); // 100 |
行われていること
ループ回数 | elmの中身 | sumの値 |
---|---|---|
1 | 10 | 0(sumの初期値)+10 = 10 |
2 | 20 | 10(ループ1終了後のsumの値)+20 = 30 |
3 | 30 | 30+30=60 |
4 | 40 | 60+40=100 |
elmにelmsの値ひとつひとつが渡ってきて、それに対してコールバック関数を実行しています。
elmという名前は別にelmじゃなくても、xやyなど好きな名前にしてOKです。
map()
全ての要素に対してコールバック関数を一度ずつ実行します。
返り値からなる新しい配列を生成します。
使用例1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | const before = [10, 20, 30, 40]; const after = before.map(elm => { // 配列の全ての要素に10を乗算した配列を返す return elm * 10; }); console.log(before); // [10, 20, 30, 40] console.log(after); // [100, 200, 300, 400] |
行われていること1
ループ回数 | elmの中身 | 処理内容(elm*10) | 返り値(return) |
---|---|---|---|
1 | 10 | 10*10=100 | [100] |
2 | 20 | 20*10=200 | [100,200] |
3 | 30 | 30*10=300 | [100,200,300] |
4 | 40 | 40*10=400 | [100,200,300,400] |
使用例2
1 2 3 4 5 6 7 8 9 10 11 12 | const before = [{key: 1, value: 10}, {key: 2, value: 20}, {key: 3, value: 30}]; const after = before.map(obj => { //keyプロパティの値だけ抜き取った別の配列を作る return obj.key;//obj['key']とも書ける }); console.log(after); // [1, 2, 3] |
行われていること2
ループ回数 | objの中身 | 処理内容(obj.key または obj[‘key’]) | 返り値(return) |
---|---|---|---|
1 | {key: 1, value: 10} | 1 | [1] |
2 | {key: 2, value: 20} | 2 | [1,2] |
3 | {key: 3, value: 30} | 3 | [1,2,3] |
filter()
全ての要素に対してコールバック関数を一度ずつ実行します。
返り値で 、true を返した要素からなる新しい配列を生成します。
使用例
1 2 3 4 5 6 7 8 9 10 11 12 | const elms = [10, 20, 30, 40]; const hoge = elms.filter(elm => { // 配列の要素が20で割り切れるものだけを抽出する return elm % 20 === 0; }); console.log(hoge); // [20, 40] |
行われていること
ループ回数 | elmの中身 | 処理内容(elm % 20 === 0 かチェックする) | 返り値(hoge) |
---|---|---|---|
1 | 10 | 20で割るとあまりが0ではないのでfalse | [] (まだ空の配列) |
2 | 20 | 20で割るとあまりは0なのでtrue | [20] (trueになった要素が入る) |
3 | 30 | 20で割るとあまりが0ではないのでfalse | [20] |
4 | 40 | 20で割るとあまりは0なのでtrue | [20, 40] |
some()
true を返す要素が見つかるまで、要素に対して一度ずつコールバック関数を実行します。
true を返す要素が見つかるとtrue を返し、ループが終わります。
使用例
1 2 3 4 5 6 7 8 9 10 11 12 13 | const elms = [10, 20, 30, 40]; const hoge = elms.some(elm => { // 要素に一つでも20以上の値があればtrueを返す return elm >= 20; }); console.log(hoge); // true |
行われていること
ループ回数 | elmの中身 | 処理内容 (elm >= 20 かチェックする) | 返り値(hoge) |
---|---|---|---|
1 | 10 | 20以上ではないのでfalse | false |
2 | 20 | 20以上なのでtrue | true (trueを返す要素が見つかったのでループはここまで) |
(3 ループ回数に含まれない) | |||
(4 ループ回数に含まれない) |
また、コールバック関数の処理内容に対してtrueとなる配列の要素がひとつもない場合は、返り値がfalseとなります。
1 2 3 4 5 6 7 8 9 10 11 12 | const elms = [10, 11, 12, 13]; const hoge = elms.some(elm => { // 要素に一つでも20以上の値があればtrueを返す return elm >= 20; }); console.log(hoge); // false |
さらに、空の配列に対してはコールバック関数の処理内容にかかわらず、falseを返します。
1 2 3 4 5 6 7 8 9 10 11 | const elms = []; const hoge = elms.some(elm => { return true; }); console.log(hoge); // false |
every()
false を返す要素が見つかるまで、要素に対して一度ずつコールバック関数を実行します。
false を返す要素が見つかるとfalse を返し、ループが終わります。
使用例
1 2 3 4 5 6 7 8 9 10 11 12 13 | const elms = [40, 30, 20, 10]; const hoge = elms.every(elm => { // 要素に一つでも25より小さい値があればfalseを返す return elm >= 25; }); console.log(hoge); // false |
行われていること
ループ回数 | elmの中身 | 処理内容 (elm >= 25かチェックする) | 返り値(return) |
---|---|---|---|
1 | 40 | 25以上なのでtrue | true |
2 | 30 | 25以上なのでtrue | true |
3 | 20 | 25以上ではないのでfalse | false (falseを返す要素が見つかったのでループはここまで) |
(4 ループ回数に含まれない) |
また、コールバック関数の処理内容に対してfalseとなる配列の要素がひとつもない場合は、返り値がtrueとなります。
1 2 3 4 5 6 7 8 9 10 11 12 13 | const elms = [40, 30, 25]; const hoge = elms.every(elm => { // 要素に一つでも25より小さい値があればfalseを返す return elm >= 25; }); console.log(hoge); // true |
さらに、空の配列に対してはコールバック関数の内容にかかわらず、trueを返します。
1 2 3 4 5 6 7 8 9 10 11 | const elms = []; const hoge = elms.every(elm => { return false; }); console.log(hoge); // true |
find()
true を返す要素が見つかるまで、要素に対して一度ずつ関数を実行します。
trueになった時点で、それに該当する値を返します。
使用例
1 2 3 4 5 6 7 8 9 10 11 12 | const elms = [10, 20, 30, 40]; const hoge = elms.find(elm => { // 配列の要素が20で割り切れるものだけを抽出する(ただし最初に条件に一致したものだけ) return elm % 20 === 0; }); console.log(hoge); // 20 |
行われていること
ループ回数 | elmの中身 | 処理内容 (elm % 20 === 0かチェックする) | 返り値(hoge) |
---|---|---|---|
1 | 10 | 20で割った余りは0ではないのでfalse | undefined |
2 | 20 | 20で割った余りは0なのでtrue | 20 (trueを返す要素が見つかったのでループはここまで) |
(3 ループ回数に含まれない) | |||
(4 ループ回数に含まれない) |
reduce()
要素に対して一度ずつコールバック関数を繰り返し、コールバック関数が最後にreturnした値がreduce全体の返り値になります。
reduceはちょっと難しいメソッドになります。
コールバック関数の引数は最大4つありますが、
currentValue,currentIndex,arrayに関しては任意なので設定しなくてもOKです。
1.accumulator(必須)
コールバック関数の返り値が蓄積されていく。
初回のループでは、initialValueがが設定されている場合はその値が設定されるが、そうでない場合は配列の0番目の要素が設定される。2. currentValue(必須)
現在処理されている配列の要素
3. currentIndex(任意)
現在処理されている配列要素のインデックス。
initialValueが設定されている場合はインデックス0から、そうでない場合は1から始まる。3. array(任意)
reduce() が呼び出された配列。
そして、reduce()の第二引数にinitialValueを設定することができます。
上でも書きましたが、initialValueが設定されていない場合、
reduce()は最初の要素を飛ばしてインデックス 1 から実行されます。
initialValue が指定されていたらインデックス 0 から処理が開始します。
よって、initialValueを設定しておいたほうが意図した挙動となるため、通常は設定したほうが良いでしょう。
使用例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | const array = [10, 20, 30]; const initialValue = {}; const obj = array.reduce((accumulator, currentValue, currentIndex) => { //配列をオブジェクトにする accumulator[`number${currentIndex}`] = currentValue; // accumulator['number'+currentIndex] = currentValueと同じ意味 return accumulator; }, initialValue); console.log(obj); // { number0: 10 number1: 20, number2: 30 } |
行われていること
ループ回数 | accumulatorの中身 (returnしたaccumulatorの値が入る) | currentValueの中身 | currentIndexの中身 | 処理内容 (オブジェクトにキーと値の追加をする) | 返り値(acc) |
---|---|---|---|---|---|
1 | {}(第二引数の空のオブジェクト) | 10 | 0 | acc[‘number0’] = 10 | {number0:10} |
2 | {number0:10} | 20 | 1 | acc[‘number1’] = 20 | {number0:10 , number1:20} |
3 | {number0:10 , number1:20} | 30 | 2 | acc[‘number2’] = 30 | {number0:10 , number1:20 , number2:30} |
reduce()はプログラミング初心者にとってはなかなか難易度が高いコードですが、先ほどご紹介したJS Binなどのツールを使って理解を深めてほしいと思います。
【参考】
MDN reduce()
reduce()はArrayにて最強……おぼえておけ。
おまけ
上記のメソッドは単体で使用することもありますが、合わせて使う時も出てきます。
ここではその一例を紹介します。
使用例
1 2 3 4 5 6 7 8 9 10 11 | //_aプロパティの値がbananaである、objectを取得する const elms = [{a: [{_a: 'apple'}, {_b: 'orange'}]},{a: [{_a: 'banana'}, {_b: 'orange'}]}] const result = elms.find(elm => { return elm.a.some(x => x._a === 'banana') }) console.log(result); // {a: [{_a: 'banana'}, {_b: 'orange'}]} |
説明
elmsの構造としては、
配列の中に、objectが2つあり(aプロパティが2つ)、そのプロパティに対する値が配列となっています。
そして、その配列の中にさらにobjectが2つ存在するといった構造です。
aプロパティまでは同じですが、その中身が異なります。
それは_aプロパティの値が片方は’apple’で、もう片方は’banana’であるという点です。
そこで、_aプロパティの値が’banana’である、object全体を取得したい場合のコードを書きました。
言葉だけだとわかりにくいので図にしました!
実行結果を見るとわかるように、ちゃんと_aプロパティの値がbananaであるobjectだけが取得できていることがわかりますね!
この記事で扱ったメソッドたち
最後に、この記事で扱ったメソッドをもう一度整理しておきましょう。
(各タイトルはページ内リンクになっています)
メソッド | 説明 |
---|---|
forEach | 全ての要素に対してコールバック関数を一度ずつ実行する。 map や filter とは異なり新しい配列は生成しない。 |
map | 全ての要素に対してコールバック関数を一度ずつ実行する。 返り値からなる新しい配列を生成する。 |
filter | 全ての要素に対してコールバック関数を一度ずつ実行する。 返り値で 、true を返した要素からなる新しい配列を生成する。 |
some | true を返す要素が見つかるまで、要素に対して一度ずつコールバック関数を実行する。 true を返す要素が見つかるとtrue を返し、ループが終わる。 |
every | false を返す要素が見つかるまで、 要素に対して一度ずつコールバック関数を実行する。 false を返す要素が見つかるとfalse を返し、ループが終わる。 |
find | true を返す要素が見つかるまで、要素に対して一度ずつコールバック関数を実行する。 trueになった時点で、それに該当する値を返す。 |
reduce | 要素に対して一度ずつコールバック関数を繰り返し、 コールバック関数が最後にreturnした値がreduce全体の返り値になる。 |
まとめ
今回は、JavaScriptのループメソッドを7つ紹介しました。
正直、この記事を読んだだけでは分からないかと思います。(笑)
重要なのはこの記事を読みながら自分で同じコードを書いてみたり、出力結果を変えてみたりして遊んでみると、新たな疑問や発見があってコードをより深く理解できるようになるのでオススメですよ!
ループ処理は頻繁に使うので、ぜひマスターしてJS脱初心者しましょう!
では!