現代的JavaScriptおれおれアドベントカレンダー2017 – 18日目

概要

配列をばらばらの配列要素だったことにして使えるやつです。

const arr = [1, 2, 3];

const arr2 = [0, ...arr];  // => [0, 1, 2, 3]

使い方

カンマ , 区切りでいろいろ書くところへ、 ...arr のようにすると、その配列の中身をばらばらに書いたかのような状態に展開してくれます。

配列とか、

const arr0 = [1, 2, 3];

const arr1 = [0, ...arr];  // => [0, 1, 2, 3]

関数とか。

function foo(a, b, c) {
  console.log(a, b, c);
}

const arr = [1, 2, 3];
foo(...arr);  // 1, 2, 3

途中でも、いくつでも

残余引数とかは末尾でしか使えなかったんですが、展開する分には十分明瞭なので、どこでもいくつでも使えます。

const arr1 = [1, 2, 3];
const arr2 = [4, 5];
const arr3 = [];

const all = ['|', ...arr1, '|', ...arr2, '|', ...arr3, '|'];  // => [ '|', 1, 2, 3, '|', 4, 5, '|', '|' ]

配列の中の配列

... を付けないとただの入れ子になります。そりゃそうじゃ。

const arr0 = [1, 2, 3];

const arr1 = [0, arr0];  // => [0, [1, 2, 3]]
const arr2 = [0, ...arr0];  // => [0, 1, 2, 3]

配列の複製

残余代入の方でも同じようなことやったけど、変数に格納する必要がない分こっちの方が良いかも。

const arr1 = [1, 2, 3];

function checkCloned(arr2) {
  console.log(arr1);
  console.log(arr2);
  console.log(arr1 === arr2);
}

checkCloned([...arr1]);
[ 1, 2, 3 ]
[ 1, 2, 3 ]
false

配列の結合

Array#conat() の代わりに使えそうです。

const arr1 = [1, 2, 3];
const arr2 = [4, 5];

const all1 = arr1.concat(arr2);  // => [1, 2, 3, 4, 5]
const all2 = [...arr1, ...arr2];  // => [1, 2, 3, 4, 5]

先頭項目を入れ替える

const arr = [1,2,3,4,5];

const [, ...secondAndLater] = arr;
const arr2 = [99, ...secondAndLater];  // => [99, 2, 3, 4, 5];

書いてはみたけど何に使えるかな。

オブジェクトのスプレッド

オブジェクトの残余代入と同様、ES2017までにはまだ存在していない未来仕様です。ES2018に入りそう。

const obj1 = { a: 1 };
const obj2 = { ...obj1 };

執筆時点でChrome、Firefoxとあと手元のNode.js v8.5で動いてます。

一方babel-preset-envのv1.6.1では対応してないっぽい。

SyntaxError: /path/to/project/main.js: Unexpected token (2:15)
  1 | const obj1 = { a: 1 };
> 2 | const obj2 = { ...obj1 };
    |                ^

(細かいバージョンは調べてません。)

Reactで使う

JSXの仕様なのでESのものではないんだけど、似たようなものなので紹介しておきます。あ、これオブジェクトの展開してるね。

you can use ... as a “spread” operator

const Button = props => {
  const { kind, ...other } = props;
  const className = kind === "primary" ? "PrimaryButton" : "SecondaryButton";
  return <button className={className} {...other} />;
};

Reactは普段使いしてないです。なんか違ってたらごめんなさい、教えてください。

その他

名前

みんな「スプレッド演算子 (spread operator)」と呼んでるけど、仕様書にそういう表現ないね。

あと配列の方は “SpreadElement” という名前が出てきてるんだけど、関数引数の方は特に名前が付いてもいない。

参考

  • ECMAScript® 2017 Language Specification
    • 12.2.5 Array Initializer … “SpreadElement” 配列のスプレッド演算子の記法
    • 12.2.5.2 Runtime Semantics: ArrayAccumulation … スプレッド演算子の処理
    • 12.3 Left-Hand-Side Expressions … 関数呼び出しの ArgumentList
    • 12.3.4 Function Calls
    • 12.3.6.1 Runtime Semantics: ArgumentListEvaluation … “…AssignmentExpression” とかの解釈
    • 9.4.4 Arguments Exotic Objects … arguments
  • スプレッド演算子 – JavaScript | MDN