自己紹介
はじめまして。TENTIALというD2CスタートアップでwebエンジニアをやっていますAmpiです。
エンジニア歴は2年目となり、TENTIALでは主にバックエンド業務を行なっています。
記事を書くに至った背景
TENTIALは、フロントにNuxt、バックエンドでExpressを採用しており、フロントもバックエンドもJavaScriptを使用しています。
必然的にJavaScriptを書く機会が多くなり、初期と比べてJavaScriptの知識も少しは増えてきたかなと思ったので、今回記事をまとめてみました。
Tips集などと銘打ってますが、基本的な文法に関する事項が多いので、その点はご了承お願いしますmm
分割代入
配列やオブジェクトを分解し、配下の要素やプロパティ値を個々の変数として宣言できます。
基本的な使い方は、下記の通りです。
- 基本
const numbers = [7, 5, 3] const[a, b, c] = numbers console.log(a) // 7 console.log(b) // 5 console.log(c) // 3 // やってることは下記と同じ // const a = numbers[0] // const b = numbers[1] // const c = numbers[2]
const user = { name: '笹本希', age: 33, gender: 'female', } const { name, age } = user console.log(name) // 笹本希 console.log(age) // 33 // やってることは下記と同じ // const name = user.name // const age = user.age
僕が業務で書く中で知ったのは下記2点です。
既定値を与えることができる
ネストした分割代入も可能
具体的には、下記のように書くことができます。
- 既定値を定めた配列の分割代入
const numbers = [7, 5] const[a = 0, b = 0, c = 0 ] = numbers console.log(a) // 7 console.log(b) // 5 console.log(c) // 0 = 既定値 // 配列numbersには2つの要素しかありませんが、既定値を定めて分割代入しているので、cがundefinedになりません。
- ネストしたオブジェクトの分割代入
const user = { name: '笹本希', age: 33, gender: 'female', info: { id: 1 } } const { gender, info: { id } } = user console.log(gender) // female console.log(id) // 1
勿論オブジェクトの分割代入する時も、既定値を定めることができます。
- 既定値を定めたネストしたオブジェクトの分割代入
const order = { name: 'insole', price: 7980, } const { info: { id = 1 } = {} } = order console.log(id) // 1 = 既定値 // orderオブジェクトにinfoプロパティが定義されてませんが、既定値を定めて分割代入しているので、エラーになりません。
個人的に特に気に入っているのは、既定値を定めたネストしたオブジェクトの分割代入です。 非同期処理などで、データの取得が上手くいかない場合を考慮して、if文を書いていたのですが、分割代入を利用することで、綺麗に書けるケースが増えた気がします。 また、バックエンド側でリクエストを受け取って、変数宣言する時等に分割代入を使用すると、無駄な重複を減らして、コードも簡潔に書けると思います。
スプレッド演算子
配列やオブジェクトを演算子が置かれた場所で展開することができます。
基本的な使い方は、下記の通りです。
- 基本
const array1 = [1, 2, 3] const array2 = [4, 5, 6] const array3 = [...array1, ...array2] console.log(array3) // 1, 2, 3, 4, 5, 6
const user = { name: '豊田翼', age: 28, } console.log(user) // { name: '豊田翼', age: 28 } const params = { ...user, gender: 'female' } console.log(params) // { name: '豊田翼', age: 28, gender: 'female' }
スプレッド演算子は至る所で使いますが、個人的に好きなのは関数の引数でスプレッド演算子を使うことです。
- 関数の引数でスプレッド演算子
const sumNumbers = (...args) => { let sum = 0 for (let arg of args) sum += arg return sum } console.log(sumNumbers(1, 2)) //3 console.log(sumNumbers(1, 2, 3)) //6
引数でスプレッド演算子を使うことで汎用性の高いメソッドを作れたりするので、良いなと思います。
あとこれはTipsっぽい技ですが、一意な配列を作成したい時に、スプレッド演算子とnew Set()
を使うと、簡潔にコードを書けるケースがあります。
- スプレッド演算子と
new Set()
の併せ技
const array1 = [1, 2, 3] const array2 = [...array1, 1, 2, 3, 4] const uniqueArray = new Set([...array1, ...array2]) console.log(array2) // 1, 2, 3, 1, 2, 3, 4 console.log(uniqueArray) // 1, 2, 3, 4
ちなみにnew Set()
は弊社テックリードに教えていただいた、素晴らしいメソッドなので、一意な配列を作成する時にfilter
とindexOf
を併用している方は、是非一度チェックしてみて下さい。
(ちなみに僕は割と最近までfilter
とindexOf
を使って一意な配列を作成していました^ ^)
実はよく知られてないreduce
配列の各要素を順番に累積して1つの値にできます。
最後は最早ただのメソッドなのですが、最近までしっかりと使いこなせていなかった、reduce
メソッドについて少し深く書いていきたいと思います。
(意外と使いどころが多く、お気に入りメソッドなので紹介します。)
基本的な使い方は下記の通りです。
- 基本
// 構文 array.reduce(callback [, initialValue]) const array1 = [1, 2, 3] const sum = array1.reduce( (accumulator, currentValue, currentIndex, array) => { return accumulator + currentValue }, 0) // 0はinitialValue console.log(sum) // 6
ここで、accumulator
, currentValue
, currentIndex
, array
, initialValue
について、簡単な説明を書いておきます。
accumulator
累積値。わかりにくいのでコードで説明していきます。currentValue
現在の値。配列の各要素currentIndex
現在のindex。配列の添字array
引数として配列を渡せる。(僕はあまり使ったことがないです。)initialValue
初期値。既定値は0。引数に渡すと一番最初の関数実行時、accumulator
にinitialValue
の値が入ります。
ちなみにcurrentIndex
, array
, initialValue
は省略することもあります。
- 一部引数省略
const array1 = [1, 2, 3] const sum = array1.reduce( (accumulator, currentValue) => { return accumulator + currentValue }) console.log(sum) // 6
僕は最近までaccumulator
があまり理解できてなかったので、reduce
は合計値を出すときに使えば良いんだな程度の認識でした。
(しかし具体的にどういう処理が行われてるかイメージできずに、気持ち悪く感じているメソッドでした。)
そこで、今回はreduce
の説明のために、let
とforEach
を使って、reduce
を書き換えたいと思います。
具体例は下記の通りです。
forEach
とreduce
(initialValue
なし)
/// reduceを使った場合 const array1 = [1, 2, 3] const sum = array1.reduce( (accumulator, currentValue) => { return accumulator + currentValue }) console.log(sum) // 6 // forEachを使った場合 let accumulator = 0 array1.forEach(value => { accumulator += value }) console.log(accumulator) // 6
accumulator
の役割が少しイメージできたのではないでしょうか?
下記コードは結果的に同じ出力結果となります。
forEach
とreduce
(initialValue
あり)
const array1 = [1, 2, 3] // reduceを使った場合 const sum = array1.reduce( (accumulator, currentValue) => { return accumulator + currentValue }, 10) console.log(sum) // 16 // letとforEachを使った場合 let accumulator = 10 array1.forEach(value => { accumulator += value }) console.log(accumulator) // 16
上記コードを簡単に説明すると、一番最初の関数実行時のaccumulator
は10で、配列をループさせながら、accumulator
に配列の各要素を足していくという挙動になります。
下記のような書き換えもできます。
- if文と
reduce
const array = [1, 2, 3, 4, 5] // reduceを使った場合。配列の最後の要素だけ削除した配列を作る const array1 = array.reduce((accumulator, currentValue, currentIndex) => { if(currentIndex !== array.length - 1){ accumulator.push(currentValue) } return accumulator }, []) console.log(array1) // [1, 2, 3, 4] // forEachを使った場合 let array2 = [] array.forEach((currentValue, currentIndex)=> { if(currentIndex !== array.length - 1){ array2.push(currentValue) } }) console.log(array2) // [1, 2, 3, 4]
個人的には、let
、 forEach
で書いていたコードが、const
で書き換えれるのは大きな魅力だと感じています。
まだまだ小さなTipsが多くあるのですが、今回は以上となります。
慣れない技術ブログで、拙い点も多くあるかと思いますが、誰かの参考になれば幸いですmm