LoginSignup
11
8

More than 3 years have passed since last update.

スプレッド構文とレスト構文と分割代入構文は違うんじゃないの?→しらん

Posted at

私の落とし所

実害がないかぎり突っ込んでも意味がなさそうなので見なかったことに。

スプレッド構文が包括的意味合いを持つのかもしれませんし。

(スプレッド構文はあくまでスプレッド演算子...を使った演算を指すだけな気がしますが特に根拠なしっと思ったらこちらを
私がスプレッド演算子と認識している理由は一部MDNでスプレッド演算子という名前でスプレッド構文へのリンクが張られていたり演算子の優先順位 - JavaScript | MDNにSpred(...)が存在したりするからですかね)

私の中だけの定義

  • スプレッド構文はiterable オブジェクトの展開の...(だいたい変数や返り値に使う)
  • レスト構文は関数定義時につかう可変長引数定義の...
  • 分割代入構文には余り表現としての...がある(...自体が分割代入構文ではないからね!)

超大雑把に頻出しそうなパターン分類として言うと

  • 式の右辺や関数呼び出し時に渡す引数にある...はスプレッド構文
  • 式の左辺にある配列内の...は分割代入構文(の余り)
  • 関数やクロージャの引数定義にある...はレスト構文

…と覚えておくと的中率が高いかもしれないけれど、まあ、その、覚えなくてもいいよね。

「あ~...えっと、この...ドットドットドット構文ね!」

発端

【JavaScript】スプレッド構文の便利な使い方まとめ - Qiita

現時点で450いいねをも集めているこのすごい記事と

スプレッド構文 - JavaScript | MDN

を見比べていて、あれ?可変長引数についてMDNにないぞってところ。

可変長引数を定義する

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

console.log(sum(1, 2, 3, 4, 5));     // 15

引数が可変長であることを明示できます。
IDEで表示され関数の利用者は引数が可変長であることがわかります。
(画像略)
arguments オブジェクトと違い、スプレッド構文で宣言された引数は Array です。
そのまま .reduce().filter().map() といった配列操作が行えます。

で、MDNのスプレッド構文の末尾にはこう

レスト構文(レストパラメータ)

レスト構文はスプレッド構文と全く同じ見た目をしていますが、Array や Object の分割代入に使われます。こちらはスプレッド構文とは逆の働きといえます: スプレッド構文が要素を展開するのに対して、レスト構文は複数の要素を集約して 1 つのオブジェクトにします。レスト構文 のページを参照してください。

これがいわゆる「可変長引数」の実現方法ですよね。

Rest parameters - JavaScript | MDN

rest parameters とは、不特定多数の引数を配列として受け取る構文です。

function sum(...theArgs) {
  return theArgs.reduce((previous, current) => {
    return previous + current;
  });
}

console.log(sum(1, 2, 3));
// expected output: 6

console.log(sum(1, 2, 3, 4));
// expected output: 10

他の記事を見てみる

Qiitaでざっとスプレッド構文で検索して

【JavaScript】「スプレッド構文」と「レスト構文」について - Qiita

のように分けて理解している方もいるんですよね。

が、この記事のレスト構文の説明だったり

分割代入(配列)

const arr = [1, 2, 3, 4, 5];
const [a, b, ...c] = arr;

console.log(a, b, c);
// 出力 1  2  [3, 4, 5]

スプレッド構文の記事
JSのスプレッド構文 - Qiita

分割代入で余った引数を...hogeで受け取る

以下のように受け取ることができます。

let [huga, poe, ...hoge] = [1, 2, 3, 4, 5];
console.log(hoge); // => [ 3, 4, 5 ]

と分割代入を一方ではレスト構文、他方ではスプレッド構文として紹介しています。

くだんの発端記事では

配列を分割する

let [a, b, ...other] = [1, 2, 3, 4, 5];

console.log(a);        // 1
console.log(b);        // 2
console.log(other);    // [3, 4, 5]

分割代入と組み合わせると配列の分割も簡単です。

と一応は書かれていますが章立てかたからそのままスプレッド構文だと受け取るかな…私は勘違いしましたし。

各章タイトルが「スプレッド構文でできること」なので配列を分割することがスプレッド構文の役割と読めてじゃあ分割代入と組み合わせるってことは分割代入[a, b, ...other]...は分割代入の構文ではなく分割代入[a, b, ...(繰り返しの転々)n]...スプレッド構文を組み合わせたって意味合いなのかな?

分割代入のMDN

Rest parameters - JavaScript | MDN
レスト構文では分割代入に言及されていないことを言及しておいて、(関連項目にはあり)

分割代入 - JavaScript | MDN

では...のことがこう書かれています。

配列の残余部分を変数に代入する

配列を分割するときに残余パターンを使用して、配列の残りの部分を取り出して変数に代入できます:

var [a, ...b] = [1, 2, 3];
console.log(a); // 1
console.log(b); // [2, 3]

…残余…パターン…
翻訳の都合か明確にスプレッド構文ともレスト構文とも書かれていません。
まあ、レストではあるのでレスト構文な気もします。
もう少し下にはさらに

オブジェクトの分割代入の残余

Rest/Spread Properties for ECMAScript 提案 (ステージ 3) は、分割代入に rest 構文を追加します。残余プロパティは、分割パターンによってすでに取り出されていない、残りの列挙可能なプロパティのキーを収集します。

let {a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40}
a; // 10 
b; // 20 
rest; // { c: 30, d: 40 }

…こっちはrest構文として
Rest parameters - JavaScript | MDN
へのリンクが張られているんですよね。

機能からいって関数の引数のレスト構文と分割代入の余りが(スプレッド構文と異なって)ほぼ同一なので頷けるのですが、
レスト構文は

rest parameters とは、不特定多数の引数を配列として受け取る構文です。

引数に対する構文であって、引数といえば関数が受け取るものという固定観念があります。
じゃあ分割代入という代入の左辺にあるものに対して引数という表現が適切かといわれるともう頭が混乱に陥ってしまって、
分割代入の...はレスト構文かと聞かれるともうあまり(残余)パターンでいいんじゃない?
と思ってしまうのでした。

になればよかったんですが

ところがどっこい奇襲はスプレッド構文から飛んできて

スプレッド構文 - JavaScript | MDN

レスト構文はスプレッド構文と全く同じ見た目をしていますが、Array や Object の分割代入に使われます。

レスト構文は分割代入に使われます

そうか…関数の引数も分割代入のそれぞれの変数も等しく引数・代入で引数・代入側があまる場合にレスト構文...が使えるてぇわけ…かな…

function f(a, b, ...theArgs) {
も関数定義にレスト構文を使っていて
let {a, b, ...rest} =
も分割代入にレスト構文を使っていて

レスト構文は不特定多数の引数を配列として受け取る構文なので、theArgsもrestも引数である。らしい。

引数ってなんでしょうね。

Rest parameters - JavaScript | MDN

説明

関数の最後の名前付き引数に "..." の接頭辞を付けると、この最後の引数は、実際に関数に渡された残りの引数による 0 からtheArgs.length の直前までの要素の配列になります。

rest parameters は、arguments により引き起こされた定型コードを減らすために導入されました。

簡単に関連付けるなら、最初は関数のためにレスト構文が用意され、その後分割代入の拡張・改善としてレスト構文の追加が提案・可決されて関数以外にも使えるようになったけどレスト構文のページの説明がちょっと古い。
ならつじつまが合いそうですね。

読めるならECMAScript読むのがやはり一番早いのかな。

あとひとりごと

...という記号単体をスプレッド演算子
って言うのかどうかこれが正式なのかどうかが問題っすよね。
仮にこれが正しいなら

スプレッド構文もレスト構文も分割代入の余りもスプレッド演算子(という...という三つの文字)を利用しているといえるわけで

JSのスプレッド演算子を理解する - Qiita

スプレッド演算子という単語の範囲内でスプレッド構文もレスト構文も分割代入の余りも並列に語られていても問題はない…ことになるかな。

昔のMDNの引用らしきものをみるとスプレッド構文をスプレッド演算子と翻訳されていた時期もあったようで混同もいたし方なしというか過去は全部MDNでも並列で書かれていた可能性もあるかもしれないし

ES2015(ES6) 入門 - Qiita

スプレッド演算子 は、複数の引数 (関数呼び出しのため) または複数の要素 (配列リテラルのため)、あるいは複数の値 (分割代入のため) が置かれるところで式が展開されます。

スプレッド演算子 - JavaScript | MDN

いいね数が正とすると私のかんぐり過ぎになっちゃうけど
結局
JavaScriptで密かに誤解されていること5選 - Qiita
スプレッド演算子は演算子になるのかに話は戻るというか
大衆が誤解して慣用的に通じているスプレッド演算子とはどういったものを指すのかになるというか
じゃあやっぱり...自体を使い方に限らずスプレッド構文やスプレッド演算子と読んじゃってもまあ実害はないんじゃないかと
一周
する
わけ
で。

11
8
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
8