JavaScriptは昔から存在するプログラミング言語なので、昔からの書き方とモダンな書き方が混在しています。

後方互換性が高い言語なので、昔からの書き方でも書けますが、新しい書き方の方がより効率的です。

今回の記事では特にスプレッド構文と分割代入に注目して、よりモダンな書き方を実現する方法を解説します。

スプレッド構文

例えば、以下のような関数を想定します。

この関数は3つの引数を取ります。

function sum(x, y, z) {
    return x + y + z;
}

この関数に対して、以下の配列 ary を引数として渡したいとします。

const ary = [2, 3, 4];

従来の書き方であれば、次のように引数を渡すでしょう。

少し冗長的で面倒に感じる方も多いと思います。

sum(ary[0], ary[1], ary[2]);

そこで使えるのが、スプレッド構文になります。

次のように、... を使うことで、変数を展開して値を渡せます。

先程の配列のindexを一つずつ指定することなく、シンプルに引数として指定できます。

sum(...ary);

配列の合成に使う

スプレッド構文は変数を展開して、処理に渡せるという点がポイントになります。

上述までの例では、配列を引数として渡すケースのみでしたが、

これを使うと、次のように配列の合成にも使えます。

const ary1 = [1, 2, 3];
const ary2 = [1, 2, ...ary1];
console.log(ary2);
// [1, 2, 1, 2, 3]

また、同様の処理は concat メソッドでも書けます。

concatは元の変数を変更しないので、受け取る形になってしまうのが注意点です。

const ary2 = [1, 2].concat(ary1);

配列をコピーする

スプレッド構文は、配列のコピーでも活躍します。

まず、スプレッド構文利用の前に、
JavaScriptでの変数が参照渡しとなる例を紹介します。

下の例では、変数から新たな変数を作成しています。

この場合、新しく作成した変数は、前の変数に与えた影響を受てしまいます。

これは参照渡しのため発生する副作用です。

const ary1 = [1, 2, 3];
const ary2 = ary1; // 新たな変数に代入(参照渡し)

// ary1にのみ変数を足す
ary1.push(4);

// ary2も影響を受ける
console.log(ary2);
// [1, 2, 3, 4]

このように変数をコピーすると、思わぬ変更が行われてしまう場合があります。

それを防ぐために、スプレッド構文が利用できます。

const ary1 = [1, 2, 3];
const ary2 = [...ary1]; // スプレッド構文で別変数を定義

// ary1だけ変数を足す
ary1.push(4);

// ary2は影響を受けない
console.log(ary2);
// [1, 2, 3]

オブジェクトでも利用できます

スプレッド構文は配列だけでなく、オブジェクトでも利用できます。

const obj = {
    a: 'b',
    c: 'd',
};

const obj2 = {...obj, ...{e: 'f'}};

console.log(obj2);

// {a: 'b', c: 'd', e: 'f'}

同じキー名があった場合、後で指定したオブジェクトが優先されるので注意してください。

以下の例では a キーの値が上書きされています。

const obj1 = {
    a: 'b',
    c: 'd',
};

const obj2 = {
    a: 1,
    b: 2,
};

const obj3 = {...obj1, ...obj2, ...{e: 'f'}};

console.log(obj3);

// {a: 1, c: 'd', b: 2, e: 'f'}

分割代入

分割代入は、変数の値をシンプルに受け取れるようにする仕組みです。

こちらも配列、オブジェクトに対して利用できます。

例えば、以下の配列を、変数 a / b / c の3つに分ける場合を想定します。

const ary = [1, 2, 3];
const a = ary[0];
const b = ary[1];
const c = ary[2];

この書き方を分割代入で書くと、次のようになります。とてもシンプルですね。

const [a, b, c] = ary;

オブジェクトでも同じです。

従来の場合は、次のようになるでしょう。

const obj = {
    a: 'aaa',
    b: 'bbb',
    c: 'ccc',
};

const a = obj.a;
const b = obj.b;
const c = obj.c;

これを分割代入で書くと、次のようになります。

オブジェクトのキーと、変数名が一致している必要がありますので注意が必要です。

const { a, b, c } = obj;

キー名と変数名を分ける場合

キー名に対して、別の変数名で受け取る場合は、次のように書きます。

以下は a キーの値を aa という変数に。

b キーの値を bb という変数。

c キーの値を cc 変数に入れるという内容です。

const { a: aa, b: bb, c: cc } = obj;

さらに、キーがなかった場合のデフォルト値も指定できます。

以下の場合、 dddd という値がデフォルト値になります。

const { a: aa, b: bb, c: cc, d = 'ddd' } = obj;

入れ子のオブジェクト

オブジェクトが入れ子になっていても、分割代入できます。

const obj = {
    a: {
        b: 'c',
    },
    aa: 'd',
}
const { a: { b }, aa } = obj;

console.log(b);  // 'c'
console.log(aa); // 'd'

分割代入の使いどころ

分割代入は オブジェクト.キー名 で何度も書くのが面倒な時に使えます。

// 従来の書き方
const name = obj.name;
const age = obj.age;

// 分割代入
const { name, age } = obj;

良くあるのは、関数の結果を分割代入で受け取るものです。

// URLへリクエストした結果のステータス、エラー、ボディーを受け取る
const { status, error, body } = getContentXXXX(url);

Framework7での実例

最近Monacaでよく利用しているFramework7でも、分割代入が使われています。以下の部分です。

export default (props, { $f7, $on }) => {
    // この中で処理を書く
});

これは従来の書き方であれば次のようになります。

この変数に入れ直す部分を省略できるのが、分割代入を利用するメリットになります。

export default function (props, params) => {
    const $f7 = params.$f7;
    const $on = params.$on;
    // この中で処理を書く
});

まとめ

スプレッド構文も分割代入も、慣れてしまうと手放せない書き方になります。

コードを読む方も、慣れてしまえばとても分かりやすいでしょう。

ぜひ活用して、あなたのアプリ開発を効率化してください。