JavaScriptに関するお知らせ

SINCE2019
>
【JS】スプレッド構文とレスト構文の使い方、違いについて

【JS】スプレッド構文とレスト構文の使い方、違いについて



こんにちは!レスト構文のレストを休憩だと思ってた Mizutani(@sirycity) です。ちなみにバブルソートのバブルも泡だと思ってた。

今日はJavaScriptの中級者への登竜門として知られている(?)、スプレッド構文とレスト構文についです。

はじめに

スプレッド構文とレスト構文はわりと最近使えるようになったJavaScriptの構文です。両方ともスプレッド演算子を使って表現されます。... こういうやつ。

スプレッド構文とレスト構文は2つともスプレッド演算子で構成される上に機能もなんか割と似てるのですげー紛らわしい。なんなら別に見分けられなくても全然問題ないんですが今回はそういう趣旨なので見分け方を使用例と一緒に見ていきたいと思います。

ちなみにスプレッドは広げる、レストは残りのやつみたいな意味です。これ分かってるとだいぶ理解しやすい...はず。

スプレッド構文

スプレッド構文は名前の通り広げます。広げられるのは文字列、配列、オブジェクトですが配列が一番多い、かつ分かりやすいと思います。

例えば普通の配列をconsole.logすると...

const arr123 = [1, 2, 3]

console.log(arr123)
// [1, 2, 3]

当然そのまんま配列が出てきます。一方、スプレッドで広げると...

const arr123 = [1, 2, 3]

console.log(arr123)
// 1
// 2
// 3

配列の中身が展開され、3つの中身がバラバラに出力されました。そう、スプレッド構文はこれだけ。

...って書くと配列バラす機能なんていつ使うんだよって感じですね。確かにバラしっぱなしってのはあんまりないです。スプレッドでよく使うのは一度バラしたものをもう1回配列にするってパターンです。ってかこの使い方がほとんど。

const arr = [... [... [... [1, 2, 3]]]]
// [1, 2, 3]

こんな感じでバラしたのをくっつけてまたバラしてまたくっつけてが何回でもできます。これを使うと配列への要素追加とかが簡単にできちゃう。こう。

const arr123 = [1, 2, 3]
const arr1234 = [...arr123 , 4]

console.log(arr1234)
// [1, 2, 3, 4]

オブジェクトでも同じことができるよ。こう。

const obj123 = {
  one: 1,
  two: 2,
  three: 3,
}

const obj1234 = {
  ... obj123,
  four: 4,
}

こんな感じ。他に使うとしたらHTMLコレクションとかsetとかmapとか配列初期化とかemptyとか配列っぽいけど配列じゃないやつを配列にする時とか。

[ ... document.getElementsByClassName('foo') ]
// HTMLコレクション
[ ... new Set(foo)]
// set
[ ... new Map([])]
// map
[ ... Array(42)]
// 配列初期化
[ ... []]
// empty

こんな風に。こうやってみるとやっぱりスプレッド構文はスプレッドするんだけどもう1回すぐに閉じるって使い方が多いですね(2回目)スプレッド構文はこんな所。

レスト構文

レスト構文は冒頭の通り残りのやつみたいな感じ。大きく分けて2種類あります。分割代入で使うパターンと引数で使うパターン。

分割代入のパターン

まずは分割代入のパターン。分割代入ってのはこういうやつ。

const [one, two ,three] = [1, 2, 3]

console.log(one) // 1
console.log(two) // 2
console.log(three) // 3

この例だと「1」と「2」と「3」の3種類に分けてるけど、例えば「1」と「残り全て」みたいな分け方をしたい時に使うのがレスト構文です。こう。

const [one, ...rest] = [1, 2, 3]

console.log(one) // 1
console.log(rest) // [2, 3]

もうこの時点でスプレッド構文と見分けつかなくなってきましたね。ともかく、レストは残り全てを配列で受け取るってのがポイント。スプレッドはバラバラにしたものを受け取るから正反対。...なんだけど、**スプレッドもたいていはバラしたあとまたすぐまとめるから(3回目)**ややこしいですね。

引数のパターン

引数でレストを使う場面もあります。例えばこの2つの関数見てみよう。

const sum2 = (n1, n2) => n1 + n2
sum2(3, 4) // 7

const sum3 = (n1, n2, n3) => n1 + n2 + n3
sum3(1, 5, 2) // 8

どっちも数字を合計するだけです。簡単!...ただこれ、同じ処理なのに引数の数が違うだけで別の関数作らなきゃいかんのでめんどいですね。こんな時に使うのがレスト。こう。

const sum = (... arg) =>
  arg.reduce((p, c) => p + c)

sum(3, 4) // 7
sum(1, 5, 2) // 8

引数がいくつだろうとargにまとめられました。...でも、これって別に残り全てじゃなくて引数をまとめただけじゃない?と思ったあなたは鋭い。↑みたいな書き方は普通はしません。なぜなら引数を配列にすればレスト使わなくても書けるから。これ見てみ。

const sum = arg =>
  arg.reduce((p, c) => p + c)

sum([3, 4]) // 7
sum([1, 5, 2]) // 8

こっちの方が楽ね。じゃあレストの存在意義は?って話になると思うけど、やっぱり残り全てって要求が来た時にはレストはめっちゃ便利です。例えば「最初の数字は除外して、残り全ての数字を合計する」とかならレストは大活躍です。どうぞ。

const sum = ([n, ...arg]) =>
  arg.reduce((p, c) => p + c)

sum([10000, 3, 4]) // 7
sum([10000, 1, 5, 2]) // 8

最初の10000は無視して残りの数字の合計ができました!しかも引数の数が違っても問題なし!これぞ残り全てを操りしレストの実力です。

スプレッドとレストを使った実例

では実際にスプレッドとレスト両方を使った例を見ていきましょう。

ところで皆さんは料理のさしすせそは知っていますか?(唐突な前フリ)こういうやつ。

const sssss = {
  sa: '砂糖',
  shi: '塩',
  su: '酢',
  se: '醤油',
  so: '味噌',
}

でも「醤油」が「せ」ってのはおかしいので「せ」は無しにしましょう。んで「そ」はソースにしよう。~~僕名古屋市民なのに...~~普通に書くとこうなります。

const newSssss = arg =>
  ({
    sa: arg.sa,
    shi: arg.shi,
    su: arg.su,
 // se: は無し,
    so: 'ソース',
  })

newSssss(sssss)

悪くはないんだけど、ちょっと長いね。もし「料理のさしすせそ」じゃなくて「料理の五十音」とかだったら50行くらいになっちゃう。こういう時にスプレッドとレストを組み合わせるとめっっちゃ簡単に書けるんですよこれが。どうぞ。

const newSssss = ({se, ...others}) =>
  ({
    ... others,
    so: 'ソース',
  })

はいこんだけ。だいぶスッキリ!そして「...」が2つ出てきました。どっちがスプレッドでどっちがレストか分かるかな?

解説

では順番に見ていきましょう。

const newSssss = ({se, ...others}) =>
  ({
    ... others,
    so: 'ソース',
  })

まず、引数の部分。({se, ...others})の部分ね!ここのothersはレスト構文です。なぜなら「せ」と「それ以外」の2つに分かれているからだね。今はseには醤油が入っていて、othersには{sa: 砂糖, shi: 塩...}みたいに残りのが詰まったオブジェクトが入っている状態です。

次に2個目の...othersの部分。こっちはスプレッド構文です。なぜならオブジェクトの{sa: 砂糖, shi: 塩...}sa: 砂糖, shi: 塩...みたいなキー:値のペアにバラしてるからです!この時点でsa, shi, su, soの4つのキー:値のペアが存在しています。

次のso: 'ソース'の部分は簡単、新しいキー:値を追加で定義します。これでsa, shi, su, so, soの5つのキー:値ペアになりました。

最後に、キー:値のペアを({})で囲ってオブジェクトにします。sa、shi、suはそのままオブジェクト内のプロパティになりますが、soだけは2つあるので後から定義したso: 'ソース'が優先されます。結果的にソースが味噌に置き換わるわけですね!以上!

スプレッドとレストの見分け方

... の直前に [ もしくは { が来てたらスプレッド、それ以外はレスト

ほぼ全てのケースはこれで見分けがつくと思います。なぜならスプレッドは殆どの場合バラしてすぐにくっつけるから(4回目)。さらに言うと、スプレッドの方が使用頻度は遥かに多いです。レストはそんなには使わないね。

そしてもう一つ、別に使えてれば名前を見分ける必要はないです。そりゃそうだ。

最後に

レストはともかくスプレッドはほんとに便利。どんどん使おう。pythonだとスターっていう似た機能もあるよ。調べてみてね。



PREV
2020-07-20
【CSS】pxとremどちらを使うか問題に対して感じたこと

NEXT
2020-07-24
【JS】100vhはみ出る問題を解決するライブラリdiv-100vhについて