「スプレッド演算子」という表現を使わない

JavaScript の文脈で ... を「スプレッド演算子」としている記述を見かけます。しかし、それはおそらく不適切で、そもそも ... は JavaScript の演算子ではないでしょう、というまとめです。

まとめ

... を使う場面は以下の4つです。

  1. Array リテラル array = [...foo, ...bar]
  2. Object リテラル object = {...foo, ...bar}
  3. 関数呼び出し foo(...bar)
  4. 引数の名前付け function foo(bar, ...baz) {}
  5. iterable からの分割代入 const [foo, ...bar] = iterable 1
  6. Object からの分割代入 const {foo, ...bar} = object 1

MDN の wiki は、はじめの3つを spread syntax、4. を rest syntax または rest parameters としています。
... は JavaScript の演算子ではありませんから、これをスプレッド「演算子」と呼ぶのはやめましょう。
特に最後の 4. は複数の値をまとめていて、動きとしてはスプレッド(展開)と逆ですから「スプレッド」の部分も正しくないです。

spread-rest.png

... は演算子ではない

演算子

演算子は関数のように、1つ以上の値から1つの値を作ります。-123-123 から -123 を作ります。1 + 2+12 から 3 を作ります。

...foo は評価できない

... が演算子だとすると、......foo のように使いますから、単項演算子ということになります。しかし、[...foo]{...foo} は値になりますが、...foo は値になりません。... を演算子と呼べない気がします。

単項演算子の種類

https://tc39.github.io/ecma262/#sec-unary-operators
によれば、単項演算子は、以下の9つです。

  1. ++
  2. --
  3. delete
  4. void
  5. typeof
  6. +
  7. -
  8. ~
  9. !

ここに ... はありません。

AST だと何になっているか?

[...foo](...foo)=>{} を分解すると、以下のようになります。それぞれ、SpreadElementRestElement になっています。これらは式の構成要素であって、それ単体で式としては評価できません。

まとめ

... は演算子ではなくて、構文の一部として考えるべきでしょう。


  1. @mysticatea さんコメントありがとうございました。 

1993contribution

小さな指摘を。

... を使う場面は以下の4つです。

実際には6つです。

  1. 配列リテラル (let a = [...b]) → Spread Element
  2. 分割代入の配列パターン (let [a, ...rest] = b) → Rest Element
  3. 関数呼び出しの実引数 (f(...a) / new F(...a)) → Spread Argument
  4. 関数定義の仮引数 (function f(...rest) {}) → Rest Parameter
  5. (ES2018 以降) オブジェクトリテラル (let a = {...b}) → Spread Property
  6. (ES2018 以降) 分割代入のオブジェクトパターン (let {a, ...rest} = b) → Rest Property
52contribution

分割代入を忘れていました。ありがとうございます。

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.