🏯

[JavaScript]分割代入とスプレッド構文について解説

に公開

はじめに

ReactやjavaScriptでよく分割代入やスプレッド構文というものが出てきます。
これらは実践的なモダンJavaScriptで出てきて使えないと大変困ります。
そこで今回はできるだけ分かりやすく分割代入とスプレッド構文についてまとめたいと思います。

オブジェクトの基本

以下のようにstudentというオブジェクトがあるとします。
「オブジェクト.プロパティ」とするとそれぞれのプロパティの値が取り出せます。

sample.js
const student = {
    name: "プログラミング太郎",
    gender: "male",
    age: 20,
    address: "Osaka",
};

const studentName = student.name;
const studentGender = student.gender;
const studentAge = student.age;
const studentAddress = student.address;

console.log(studentName);
console.log(studentGender);
console.log(studentAge);
console.log(studentAddress);

出力結果は以下の通りです。

プログラミング太郎
male
20
Osaka

しかしこの記述だと長くなってしまいます。
そこで分割代入を使って楽に記述してみましょう。

オブジェクトの分割代入

以下のようにconst {プロパティ名,・・・} = オブジェクト名;と書くことで先程の4行の記述を1行にすることが出来ます。
記述が楽にかつ分かりやすくなりました。
更に、プロパティの名前をそのまま使用できるので見返すときなどに分かりやすくなります。

sample.js
//分割代入
const student = {
    name: "プログラミング太郎",
    gender: "male",
    age: 20,
    address: "Osaka",
};

const { name, gender, age, address } = student;

console.log(name);
console.log(gender);
console.log(age);
console.log(address);

配列の分割代入

オブジェクトの時と同じように配列も分割代入することが可能です。
まずは単純に一つ一つの要素を取り出します。

sample.js
const array = ["Tanaka", "Noda", "Watanabe"];

const str1 = array[0];
const str2 = array[1];
const str3 = array[2];

console.log(str1);
console.log(str2);
console.log(str3);

出力結果は以下の通りです。

Tanaka
Noda
Watanabe

これも分割代入を利用すれば以下のように簡単に記述することが出来ます。

sample.js
const array = ["Tanaka", "Noda", "Watanabe"];

const [ str1, str2, str3 ] = array;

console.log(str1);
console.log(str2);
console.log(str3);

スプレッド構文

先程のように一つ一つの取り出すのではなく、例えばTanakaだけ取り出して他は配列のままで良いという場合はよくあります。
このような場合にスプレッド構文を利用します。
今回はTanakaだけを取り出して他は配列のままにします。
その場合は、const [ str1, ...other] = array;と記述します。

sample.js
const array = ["Tanaka", "Noda", "Watanabe"];

const [ str1, ...other] = array;

console.log(str1);
console.log(other);

出力結果は以下の通りです。

Tanaka
[ 'Noda', 'Watanabe' ]

スプレッド構文はもちろんオブジェクトでも使用可能です。
先程のstudentというオブジェクトを例に上げて説明します。
今回はnameの値だけを取り出してその他はそのままにします。

sample.js
const student = {
    name: "プログラミング太郎",
    gender: "male",
    age: 20,
    address: "Osaka",
};

const { name, ...more } = student;
console.log(name);
console.log(more);

出力結果は以下の通りです。

プログラミング太郎
{ gender: 'male', age: 20, address: 'Osaka' }

活用編

分割代入とスプレッド構文についてざっくりと理解していただいたと思います。
これからは、実際によくある場面ついて記載します。
例えば以下のdataというオブジェクトは記事の内容を示しています。
ここでユーザーが記事を投稿する際に、記事の内容を示すtextがあったり無かったりすることがあります。
単純に以下のようにtextの内容が空であれば、空で返ってくるので大丈夫なのですが、プログラムの作りによってはtextというプロパティ自体を無くしてくるものが中にはあります。その場合に、console.log(text);を実行するとundefinedになります。
undefined自体は厳密にはエラーでは無いのですが、プログラム次第ではundefinedにより上手く動作しない場合があります。

sample.js
const data = {
    id: "01",
    title: "タイトル1",
    text: "",
};

const { id, title, text } = data;
sample.js
const data = {
    id: "01",
    title: "タイトル1",
    //text: "",
};

const { id, title, text } = data;

このような場面の際に分割代入は便利です。textは自由記入なので以下のように初期値を渡します。

sample.js
const data = {
    id: "01",
    title: "タイトル1",
    //text: "",
};

const { id, title, text = "" } = data;

console.log(id);
console.log(title);
console.log(text);

今回はtextというプロパティ自体がなくなっており先程のように初期値を渡さないとundefinedが返ってきます。
しかし今回は初期値を渡しているので以下のように空文字が返ってきます。

01
タイトル1

以下のようにtextに内容がある場合でも問題なく動作します。

sample.js
const data = {
    id: "01",
    title: "タイトル1",
    text: "内容1",
};

const { id, title, text = "" } = data;

console.log(id);
console.log(title);
console.log(text);

出力結果は以下の通りです。

01
タイトル1
内容1

このように分割代入は初期値も指定することが出来ます。
最初に示した「オブジェクト.プロパティ」の形でも同じようなことは出来るのですがif文などを使い長くなってしまいます。しかし分割代入を使うことで簡潔に書くことが出来ます。

関数編

分割代入はオブジェクトや配列だけでは無く、関数の戻り値にも使うことが出来ます。

sample.js
function getData() {
    return [ "大阪", "東京" ];
}

const [ data1, data2 ] = getData();
console.log(data1);
console.log(data2);

出力結果は以下の通りです。

大阪
東京

また、関数も同様にreturnが決まったフォーマットで返って来ない場合がよくあります。例えば関数の中でエラーが発生しnullで返ってきたりreturnが返ってこない場合があります。
もし以下のようにnullで返ってきてしまうとエラーが発生します。

sample.js
function getData() {
    // return [ "大阪", "東京" ];
    return null;
}

const [ data1, data2 ] = getData();
console.log(data1);
console.log(data2);

以下のようなエラーが、、、

Uncaught TypeError: getData is not a function or its return value sample.js:56 is not iterble at sample.js:56:28

これを解決するためには以下のようにconst [ data1, data2 ] = getData() || "";と条件分岐を作ります。

sample.js
function getData() {
    // return [ "大阪", "東京" ];
    return null;
}

const [ data1, data2 ] = getData() || "";
console.log(data1);
console.log(data2);

出力結果は以下の通りです。

undefined
undefined

もちろんundefinedで返ってくるのでプログラム次第ではエラーになってしまう可能性はあります。しかし先のようにいきなり即時停止されるよりはよっぽどましです。
また、以下のようにしっかりと戻り値が返ってくる場合でも問題なく動作します。

sample.js
function getData() {
    return [ "大阪", "東京" ];
}

const [ data1, data2 ] = getData() || "";
console.log(data1);
console.log(data2);

出力結果は以下の通りです。

大阪
東京

このように関数に対しても、不確かな値について予防線を張れる事が出来るのが分割代入の良い点でもあります。しかしケースバイケースなので必ずこの書き方というわけではありません。

ネスト編

次に以下のようにオブジェクトの中にオブジェクトというネストみたいな状況はよくあると思います。このような場合でも分割代入は使用できます。

sample.js
const place = {
    area: "関東",
    pre: {
        tokyo: "東京",
        saitama: "埼玉",
        kanagawa: "神奈川"
    },
};

const {
    area, 
    pre:{tokyo, saitama, kanagawa},
} = place;

console.log(area);
console.log(tokyo);
console.log(saitama);
console.log(kanagawa);

出力結果は以下の通りです。

関東
東京
埼玉
神奈川

ただし、上記のように一つずつ取り出す際には大丈夫なのですが、preだけを取り出したい場合にconsole.log(pre);としてしまうとエラーが発生します。
preをまとめて取り出したい場合は先程記載したスプレッド構文を利用すると便利です。

sample.js
const place = {
    area: "関東",
    pre: {
        tokyo: "東京",
        saitama: "埼玉",
        kanagawa: "神奈川"
    },
};

const {area, ...other} = place;
console.log(area);
console.log(other);

出力結果は以下の通りです。

関東
{ pre: { tokyo: '東京', saitama: '埼玉', kanagawa: '神奈川' } }

スプレッド構文を使用しなくても以下のようにpreを2回宣言する(バラしてるだけのpre,使うpre)と問題なく動作します。

sample.js
const place = {
    area: "関東",
    pre: {
        tokyo: "東京",
        saitama: "埼玉",
        kanagawa: "神奈川"
    },
};

const {
    area, 
    pre:{tokyo, saitama, kanagawa},
    pre,
} = place;

console.log(area);
console.log(tokyo);
console.log(saitama);
console.log(kanagawa);
console.log(pre);

出力結果は以下の通りです。

関東
東京
埼玉
神奈川
{ tokyo: '東京', saitama: '埼玉', kanagawa: '神奈川' }

宣言型の関数編

以下のような宣言型の関数はReactなどでよくあるかと思います。

sample.js
const place = {
    area: "関東",
    pre: {
        tokyo: "東京",
        saitama: "埼玉",
        kanagawa: "神奈川"
    },
};

const text = (place) => {
    console.log(`${place.area}には${place.pre.tokyo},${place.pre.saitama},${place.pre.kanagawa}などがあります。`);
}

text(place);

出力結果は以下の通りです。

関東には東京,埼玉,神奈川などがあります。

しかし、いちいちplace.pre.tokyoなどと書くのは煩わしいですよね。
そこで分割代入に書き換えます。
textの引数をplaceから{ area, pre: { tokyo, saitama, kanagawa }}に変更します。
するとconsole.jogの記述が簡単になります。

sample.js
const place = {
    area: "関東",
    pre: {
        tokyo: "東京",
        saitama: "埼玉",
        kanagawa: "神奈川"
    },
};

const text = ({ area, pre: { tokyo, saitama, kanagawa }}) => {
    console.log(`${area}には${tokyo},${saitama},${kanagawa}などがあります。`);
}

text(place);

これはReactでよく見る形だと思います。
Reactで分割代入は以下のようなところで使用されます。

App.js
const Todo = ({text, name}) => {
    const [set] = useState()
    return(
        <div>
            {text}
        </div>
    );
}

まとめ

今回は分割代入とスプレッド構文についての解説をしました。

Discussion