はじめに
JavaScriptのArrayやObjectには便利なメソッドが備わっています.
適切に使ってコードを読みやすく保ちましょう,というお話です.
個人的によく使うメソッドを紹介していきます.
アロー関数式
本記事のコードではアロー関数式を用います.アロー関数式は関数式の代替構文です.
以下の2文は同じ意味になります.(他にも書き方は色々あります.)
// 伝統的な関数
let double = function (val) {
return val*2
}
// アロー関数
let double = (val) => val*2
Arrayのメソッド
1. find
引数として与えたテスト関数を配列の先頭要素から適用し,一番最初に合格した(truthyな値を返した)要素を返します.どれも合格しなければundefined
を返します.
let ary = [
{val: 100, name: 'aaa'},
{val: 200, name: 'bbb'},
{val: 300, name: 'ccc'},
]
ary.find((elm) => elm.val == 200)
// -> {val: 200, name: 'bbb'}
ary.find((elm) => elm.name == 'ddd')
// -> undefined
2. findIndex
引数として与えたテスト関数を配列の先頭要素から適用し,一番最初に合格した(truthyな値を返した)要素の位置を返します.どれも合格しなければ-1
を返します.
let ary = [
{val: 100, name: 'aaa'},
{val: 200, name: 'bbb'},
{val: 300, name: 'ccc'},
]
ary.findIndex((elm) => elm.val == 200)
// -> 1
ary.findIndex((elm) => elm.name == 'ddd')
// -> -1
3. indexOf
引数として与えた要素を先頭から検索し,一番最初に見つけた位置を返します.見つからなければ-1
を返します.
let ary = [
{val: 100, name: 'aaa'},
{val: 200, name: 'bbb'},
{val: 300, name: 'ccc'},
]
let target = ary[1]
ary.indexOf(target)
// -> 1
要素の中身までは見ません.Objectなどの場合は同じインスタンスでなければいけません.
[0,1,2].indexOf(2)
// -> 2
[{val:0}, {val:1}, {val:2}].indexOf({val:2})
// -> -1
4. includes
引数として与えた要素が配列内に含まれるかどうかをtrue
かfalse
で返します.
let ary = [
{val: 100, name: 'aaa'},
{val: 200, name: 'bbb'},
{val: 300, name: 'ccc'},
]
let target = ary[1]
ary.includes(target)
// -> true
こちらもindexOf
と同様,要素の中身までは見ません.
[0,1,2].includes(2)
// -> true
[{val: 0}, {val: 1}, {val: 2}].includes({val: 2})
// -> false
5. filter
引数として与えたテスト関数に合格する要素のみを残し,新しい配列を生成して返します.
let ary = [{val: 100}, {val: 150}, {val: 200}, {val: 250}]
ary.filter((elm) => elm.val%100 == 0)
// -> [{val: 100}, {val: 200}]
ary.filter((elm) => elm.val >= 200)
// -> [{val: 200}, {val: 250}]
6. map
引数として与えた関数を各要素に適用し,その結果からなる新しい配列を生成して返します.
let ary = [
{val: 100, name: 'aaa'},
{val: 200, name: 'bbb'},
{val: 300, name: 'ccc'},
]
ary.map((elm) => {
return {val: elm.val/100, name: elm.name[0]}
})
// -> [{val: 1, name:'a'}, {val: 2, name:'b'}, {val: 3, name:'c'}]
7. every
配列の全要素が,引数として与えたテスト関数に合格するかどうかをtrue
かfalse
で返します.
let ary = [
{val: 100, name: 'aaa'},
{val: 200, name: 'bbb'},
{val: 300, name: 'ccc'},
]
ary.every((elm) => elm.val%100 == 0)
// -> true
ary.every((elm) => elm.val == 200)
// -> false
8. some
配列内の少なくとも1つの要素が,引数として与えたテスト関数に合格するかどうかをtrue
かfalse
で返します.
let ary = [
{val: 100, name: 'aaa'},
{val: 200, name: 'bbb'},
{val: 300, name: 'ccc'},
]
ary.some((elm) => elm.val%100 == 0)
// -> true
ary.some((elm) => elm.val == 200)
// -> true
Objectのメソッド
9. assign
1つ以上のコピー元オブジェクトから列挙可能なプロパティを,コピー先オブジェクトにコピー(シャローコピー)します.
let obj1 = {val: 100, name: 'aaa'}
let obj2 = {val: 200, age: 20}
Object.assign(obj1, obj2)
// obj1 -> {val: 200, name: 'aaa', age: 20}
// obj2 -> {val: 200, age: 20}
複数のオブジェクトを結合した「新しい」オブジェクトを作成したい場合は以下のようにも書けます.
let new_obj = {...obj1, ...obj2}
// new_obj -> {val: 200, name: 'aaa', age: 20}
// obj1 -> {val: 100, name: 'aaa'}
// obj2 -> {val: 200, age: 20}
10. fromEntries
キーと値の組み合わせのリストから,オブジェクトに変換します.
(個人的にこのメソッドは分かりづらいので,for文で書いても良いと思います.)
let items = [['val', 100], ['name', 'aaa'], ['age', 20]]
Object.fromEntries(items)
// -> {val: 100, name: 'aaa', age: 20}
for文で書くなら以下.
let items = [['val', 100], ['name', 'aaa'], ['age', 20]]
let obj = {}
for (let [k,v] of items) {
obj[k] = v;
}
// obj -> {val: 100, name: 'aaa', age: 20}
なぜ用意されているメソッドを使うべきか?
本記事で紹介したメソッドの基本動作は簡単で,少しプログラミングを勉強した方であればfor文などを使って自力で書けると思います.
であればなぜJSに用意されているメソッドをわざわざ覚えて使うのか?
私は以下の理由を挙げます.
- バグを生んでしまう可能性が減る
- 何の処理なのか一目で分かる
- 行数が少なくなり,プログラムの見通しが良くなる
いくら経験を積んでも,間違い(=バグ)は起きます.少しでもバグの発生要因になることは減らしましょう.
また,未来の自分や他人がそのプログラムを見るときのために,わかりやすさは重要です.
JavaScriptの動作は比較的早いですし,ブラウザであれば処理するデータもそこまで大きくないことが多いです.
そのため個人的には,少しぐらい処理が冗長になったとしても,用意されているメソッドを使うべきだと思っています.
参考
紹介した以外にもいくつかのメソッドが用意されています.
詳しい仕様などはMDN Web Docsが参考になると思います.