JavaScript の文脈で ...
を「スプレッド演算子」としている記述を見かけます。しかし、それはおそらく不適切で、そもそも ...
は JavaScript の演算子ではないでしょう、というまとめです。
まとめ
...
を使う場面は以下の4つです。
- Array リテラル
array = [...foo, ...bar]
- Object リテラル
object = {...foo, ...bar}
- 関数呼び出し
foo(...bar)
- 引数の名前付け
function foo(bar, ...baz) {}
- iterable からの分割代入
const [foo, ...bar] = iterable
1 - Object からの分割代入
const {foo, ...bar} = object
1
MDN の wiki は、はじめの3つを spread syntax、4. を rest syntax または rest parameters としています。
...
は JavaScript の演算子ではありませんから、これをスプレッド「演算子」と呼ぶのはやめましょう。
特に最後の 4. は複数の値をまとめていて、動きとしてはスプレッド(展開)と逆ですから「スプレッド」の部分も正しくないです。
...
は演算子ではない
演算子
演算子は関数のように、1つ以上の値から1つの値を作ります。-123
の -
は 123
から -123 を作ります。1 + 2
の +
は 1
と 2
から 3 を作ります。
...foo
は評価できない
...
が演算子だとすると、...
は ...foo
のように使いますから、単項演算子ということになります。しかし、[...foo]
や {...foo}
は値になりますが、...foo
は値になりません。...
を演算子と呼べない気がします。
単項演算子の種類
https://tc39.github.io/ecma262/#sec-unary-operators
によれば、単項演算子は、以下の9つです。
++
--
delete
void
typeof
+
-
~
!
ここに ...
はありません。
AST だと何になっているか?
[...foo]
、(...foo)=>{}
を分解すると、以下のようになります。それぞれ、SpreadElement
と RestElement
になっています。これらは式の構成要素であって、それ単体で式としては評価できません。
まとめ
...
は演算子ではなくて、構文の一部として考えるべきでしょう。
-
@mysticatea さんコメントありがとうございました。 ↩
小さな指摘を。
実際には6つです。
let a = [...b]
) → Spread Elementlet [a, ...rest] = b
) → Rest Elementf(...a)
/new F(...a)
) → Spread Argumentfunction f(...rest) {}
) → Rest Parameterlet a = {...b}
) → Spread Propertylet {a, ...rest} = b
) → Rest Property分割代入を忘れていました。ありがとうございます。