スプレッド構文を使うと、関数呼び出しでは 0 個以上の引数として、Array リテラルでは 0 個以上の要素として、Object リテラルでは 0 個以上の key-value のペアとして、Array や String などの iterable オブジェクトをその場で展開します。
The source for this interactive example is stored in a GitHub repository. If you'd like to contribute to the interactive examples project, please clone https://github.com/mdn/interactive-examples and send us a pull request.
構文
関数呼び出し
myFunction(...iterableObj);
Array リテラル
[...iterableObj, '4', 'five', 6];
Object リテラル(ECMAScript 2018 の新機能)
let objClone = { ...obj };
例
関数呼び出しで使う
apply を置き換える
Array の要素を引数にして関数を呼び出すには Function.prototype.apply を使うのが一般的です。
function myFunction(x, y, z) { }
var args = [0, 1, 2];
myFunction.apply(null, args);
スプレッド構文を使うと、上のコードは次のように書けます。
function myFunction(x, y, z) { }
var args = [0, 1, 2];
myFunction(...args);
スプレッド構文は、引数の何番目でも使えます。また、複数回使えます。
function myFunction(v, w, x, y, z) { }
var args = [0, 1];
myFunction(-1, ...args, 2, ...[3]);
new 演算子と併用する
コンストラクタを new 演算子で呼ぶとき、 引数リストを Array で指定するために apply を使うことはできません。Function.prototype.apply はコンストラクタを関数として呼び出してしまうからです。
スプレッド構文を使えば、Array の要素をコンストラクタの引数として簡単に指定できます。
var dateFields = [1970, 0, 1]; // 1 Jan 1970 var d = new Date(...dateFields);
スプレッド構文を使わずに同じ結果を得るには、専用の関数を使う間接的な手段を取らざるをえません。
function applyAndNew(constructor, args) {
function partial () {
return constructor.apply(this, args);
};
if (typeof constructor.prototype === "object") {
partial.prototype = Object.create(constructor.prototype);
}
return partial;
}
function myConstructor () {
console.log("arguments.length: " + arguments.length);
console.log(arguments);
this.prop1="val1";
this.prop2="val2";
};
var myArguments = ["hi", "how", "are", "you", "mr", null];
var myConstructorWithArguments = applyAndNew(myConstructor, myArguments);
console.log(new myConstructorWithArguments);
// (internal log of myConstructor): arguments.length: 6
// (internal log of myConstructor): ["hi", "how", "are", "you", "mr", null]
// (log of "new myConstructorWithArguments"): {prop1: "val1", prop2: "val2"}
Array リテラルで使う
より強力な配列リテラル
Array リテラルでスプレッド構文を使うと、すでにある Array を一部とする新しい配列を簡単に作れます。スプレッド構文を使わない場合、Array リテラルだけでは不十分で、push, splice, concat などを使うコードを書かなければなりません。
var parts = ['shoulders', 'knees']; var lyrics = ['head', ...parts, 'and', 'toes']; // ["head", "shoulders", "knees", "and", "toes"]
関数の引数と同様に、... は Array リテラルのどこでも、何回でも使えます。
Array を複製する
var arr = [1, 2, 3]; var arr2 = [...arr]; // arr.slice() のような動きです arr2.push(4); // arr2 は [1, 2, 3, 4] になります // arr は変更されません
注意:コピーは 1 段階の深さで行われます。そのため、次の例のような多次元配列のようなオブジェクトをコピーする場合には適さないでしょう。Object.assign() についても同じことが言えます。
var a = [[1], [2], [3]]; var b = [...a]; b.shift().shift(); // 1 // a は影響を受けています: [[], [2], [3]]
Array を連結する
Array の連結には Array.concat がよく使われます。
var arr1 = [0, 1, 2]; var arr2 = [3, 4, 5]; // arr1 の後ろに arr2 を連結した新しい配列をつくる arr1 = arr1.concat(arr2);
スプレッド構文を使うと、次のように書けます。
var arr1 = [0, 1, 2]; var arr2 = [3, 4, 5]; arr1 = [...arr1, ...arr2];
Array.unshift は、既存の配列の先頭に配列を挿入するためによく使われます。
var arr1 = [0, 1, 2]; var arr2 = [3, 4, 5]; // Prepend all items from arr2 onto arr1 Array.prototype.unshift.apply(arr1, arr2) // arr1 is now [3, 4, 5, 0, 1, 2]
スプレッド構文を使うと、次のように書けます(ただし、この記述だと新しい配列を生成して arr1 に代入しています。Array.unshift と異なり、元の arr1 に追加していません)。
var arr1 = [0, 1, 2]; var arr2 = [3, 4, 5]; arr1 = [...arr2, ...arr1]; // arr1 is now [3, 4, 5, 0, 1, 2]
Object リテラルで使う
Rest/Spread Properties for ECMAScript proposal (stage 4) では、Object リテラルでのスプレッド構文が追加されています。スプレッド構文の対象となるオブジェクトの列挙可能なプロパティを、新しいオブジェクトにコピーします。
prototype を除いた浅いコピーの作成や、マージしたオブジェクトの作成が Object.assign() を使うよりも短いコードで書けます。
var obj1 = { foo: 'bar', x: 42 };
var obj2 = { foo: 'baz', y: 13 };
var clonedObj = { ...obj1 };
// Object { foo: "bar", x: 42 }
var mergedObj = { ...obj1, ...obj2 };
// Object { foo: "baz", x: 42, y: 13 }
Object.assign() は setters をトリガーしますが、スプレッド構文はトリガーできません。
スプレッド構文は Object.assign() 関数を置き換えたり模倣することはできません。
var obj1 = { foo: 'bar', x: 42 };
var obj2 = { foo: 'baz', y: 13 };
const merge = ( ...objects ) => ( { ...objects } );
var mergedObj = merge ( obj1, obj2);
// Object { 0: { foo: 'bar', x: 42 }, 1: { foo: 'baz', y: 13 } }
var mergedObj = merge ( {}, obj1, obj2);
// Object { 0: {}, 1: { foo: 'bar', x: 42 }, 2: { foo: 'baz', y: 13 } }
上記の例でスプレッド構文は期待通りに動きません。レストパラメーターは配列で、オブジェクトリテラルに配列として展開されます。
iterable オブジェクトだけに使えます
Object リテラルで使う場合を除き、スプレッド構文は iterable オブジェクトだけに使えます。iterable でないオブジェクトでは、TypeError 例外となります。
var obj = {'key1': 'value1'};
var array = [...obj]; // TypeError: obj is not iterable
大量の値を展開する場合
JavaScript エンジンには、引数の個数に上限があります。関数呼び出しでのスプレッド構文では、引数の個数がその上限を超えてしまう可能性に留意してください。詳細は apply() のページを参照してください。
レスト構文(レストパラメータ)
レスト構文はスプレッド構文と全く同じ見た目をしていますが、Array や Object の分割代入に使われます。こちらはスプレッド構文とは逆の働きといえます: スプレッド構文が要素を展開するのに対して、レスト構文は複数の要素を集約して 1 つのオブジェクトにします。レスト構文 のページを参照してください。
仕様
| 仕様 | ステータス | コメント |
|---|---|---|
| ECMAScript 2015 (6th Edition, ECMA-262) | 標準 | 配列初期化子, 引数リスト のセクションで定義されました。 |
| ECMAScript 2018 (ECMA-262) | 標準 | オブジェクト初期化子で定義されました。 |
| ECMAScript Latest Draft (ECMA-262) | ドラフト | 変更はありません。 |
| ECMAScript Latest Draft (ECMA-262) | ドラフト | 変更はありません。 |
ブラウザー実装状況
| デスクトップ | モバイル | サーバー | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Spread in array literals | Chrome 完全対応 46 | Edge 完全対応 12 | Firefox 完全対応 16 | IE 未対応 なし | Opera 完全対応 37 | Safari 完全対応 8 | WebView Android 完全対応 46 | Chrome Android 完全対応 46 | Firefox Android 完全対応 16 | Opera Android 完全対応 37 | Safari iOS 完全対応 8 | Samsung Internet Android 完全対応 5.0 | nodejs
完全対応
5.0.0
|
| Spread in function calls | Chrome 完全対応 46 | Edge 完全対応 12 | Firefox 完全対応 27 | IE 未対応 なし | Opera 完全対応 37 | Safari 完全対応 8 | WebView Android 完全対応 46 | Chrome Android 完全対応 46 | Firefox Android 完全対応 27 | Opera Android 完全対応 37 | Safari iOS 完全対応 8 | Samsung Internet Android 完全対応 5.0 | nodejs
完全対応
5.0.0
|
| Spread in destructuring | Chrome 完全対応 49 | Edge 未対応 なし | Firefox 完全対応 34 | IE 未対応 なし | Opera 完全対応 37 | Safari ? | WebView Android 完全対応 49 | Chrome Android 完全対応 49 | Firefox Android 完全対応 34 | Opera Android 完全対応 37 | Safari iOS ? | Samsung Internet Android 完全対応 5.0 | nodejs 完全対応 あり |
| Spread in object literals | Chrome 完全対応 60 | Edge 未対応 なし | Firefox 完全対応 55 | IE 未対応 なし | Opera 完全対応 47 | Safari 完全対応 11.1 | WebView Android 完全対応 60 | Chrome Android 完全対応 60 | Firefox Android 完全対応 55 | Opera Android ? | Safari iOS 完全対応 11.3 | Samsung Internet Android 完全対応 8.2 | nodejs
完全対応
8.3.0
|
凡例
- 完全対応
- 完全対応
- 未対応
- 未対応
- 実装状況不明
- 実装状況不明
- 実験的。動作が変更される可能性があります。
- 実験的。動作が変更される可能性があります。
- ユーザーが明示的にこの機能を有効にしなければなりません。
- ユーザーが明示的にこの機能を有効にしなければなりません。