【ES2015】分割代入の基本と便利な使い方
分割代入 (Destructuring assignment)とは
ES2015で導入されていた機能でざっくり言うと、複数の値を、一度に複数の変数に代入するためのもの。
配列での使い方
配列の各要素を取得する基本型。
const ary = [1, 2, 3]; const [a, b, c] = ary; console.log(a); // -> 1 console.log(b); // -> 2 console.log(c); // -> 3
特定の要素だけ取得する場合は、それ以外の要素に対応する箇所は空欄のままカンマで区切る。
const ary = [1, 2, 3]; const [, , a] = ary; console.log(a); // -> 3
空欄のままカンマで区切った要素は undefined
が入る。
const [a, b, c] = [1, , 3]; console.log(b); // -> undefined
スプレッド演算子を使って複数の要素も取得可能。
下記の場合は指定されていない残りの値が変数 c
に配列として代入される。
const ary = [1, 2, 3, 4, 5]; const [a, , b, ...c] = ary; console.log(a); // -> 1 console.log(b); // -> 3 console.log(c); // -> [4, 5]
ES2015で導入されたデフォルト引数の記述形式で、規定値の指定ができる。
const [a = 1, b = 2, c = 3] = [, , 5]; console.log(a); // -> 1 console.log(b); // -> 2 console.log(c); // -> 5
オブジェクトでの使い方
オブジェクトから一度に複数のkeyの値を取り出すことができる。
const bob = { age: 30, gender: 'male', country: 'USA' }; const {age, gender} = bob; console.log(age); // -> 30 console.log(gender); // -> male
keyと同名の変数でないといけないかというとそんなことはなく、:
(コロン)で繋いで変数名を定義すると、その変数名に変更できる。
const {age: nenrei , gender: seibetsu} = bob; console.log(nenrei); // -> 30 console.log(seibetsu); // -> male
存在しないkeyを代入しようとすると、配列の時と同様に undefined
が入る。
const {weight: taiju} = bob; console.log(taiju); // -> undefined
配列と同様にデフォルト引数の形式で規定値の指定が可能。
const { age: nenrei = 20, gender: seibetsu, weight: taiju = '70kg' } = bob; console.log(nenrei); // -> 30 console.log(seibetsu); // -> male console.log(taiju); // -> 70kg
便利な使い方
値の入れ替え
変数同士の値の入れ替えが簡単に行える。
let [a, b] = [1, 2]; [a, b] = [b, a]; console.log(a); // -> 2 console.log(b); // -> 1
複数の返り値の取得
配列もしくはオブジェクト形式の返り値を一気に取得できる。
もちろんいらないものは除外可能。
function power(num) { return [num, num**2, num**3]; } const [a, b, c] = power(3); console.log(a); // -> 3 console.log(b); // -> 9 console.log(c); // -> 27
関数の引数を分かりやすく表現
基本的に、引数が多い関数はちゃんと考慮しないと引数にどんな値を入れたらいいかわかりにくくなるが、分割代入を応用すると分かりやすく明示することができる。
例えば下記は、move関数の呼び出しと宣言をしているが、どんな引数をどんな順番で入れればよいか分かりにくい。
// 呼び出し move('.target', 10, 30, 300, 'ease-in'); // 宣言 function move(targetSelector, x, y, duration, easing) { // 何らかの処理… }
オブジェクトを引数に使えば、関数の呼び出し側では分かりやすくなるが、関数の宣言個所では仮引数が一つとなり、どんなプロパティのオブジェクトを渡せばよいか、すぐには分かりにくい。
// 呼び出し move({ targetSelector:'.hoge', x: 10, y: 30, duration: 300, easing: 'ease-in' }); // 宣言 function move(params) { const targetSelector = params.targetSelector; const x = params.x; const y = params.y; const duration = params.duration; const easing = params.easing; }
分割代入を使って宣言を書くと下記になる。
引数に渡すべきオブジェクトのプロパティの名前と値のデータ型の把握がしやすい。
※引数が空でも問題がないように、デフォルト引数として {}
を代入。
// 宣言 function move({targetSelector = '.target', x = 0, y = 0, duration = 0, easing = 'linear'} = {}) { // 何らかの処理… }
ループ処理
foreach
などのループ処理のときに使用すると、ダイレクトにプロパティ名で参照できてコードの見通しがよくなる。
const people = [ {name: 'Bob', age: 30, country: 'USA'}, {name: 'Anne', age: 25, country: 'Germany'}, {name: 'Taro', age: 22, country: 'Japan'} ]; // 通常時(分割代入を使わない) people.forEach(person => { console.log(`名前:${person.name} 年齢:${person.age} 国籍:${person.country}`); }); // 分割代入を使う people.forEach(({name, age, country}) => { console.log(`名前:${name} 年齢:${age} 国籍:${country}`); });
JSONや、ネストされたオブジェクトや配列から値を取得
普通に取ろうとすると面倒なデータからも、分割代入を使うと階層をたどって取得できる。
const people = [ { name: 'Bob', age: 30, country: 'USA', family: { child: [ { name: 'Jack', age: 8, hobby: ['video game', 'football'] }, { name: 'Tom', age: 1, hobby: ['walk', 'eat', 'sleep'] } ] } }, { name: 'Anne', age: 25, country: 'Germany', family: { child: [ { name: 'Clara', age: 3, hobby: ['play house', 'sing'] } ] } } ]; const [bob, anne] = people; const { name: bobName, age: bobAge, country: bobCountry, family: bobFamily, family: { child: [...bobChild], child: [bobChild1, bobChild2], child: [{ name: bobChild1Name, age: bobChild1Age, hobby: [...bobChild1Hobby] }, { name: bobChild2Name, age: bobChild2Age, hobby: [bobChild2Hobby1, bobChild2Hobby2] }] } } = bob; console.log(bob); // -> {name: "Bob", age: 30, country: "USA", family: {…}} console.log(bobName); // -> Bob console.log(bobFamily); // -> {child: Array(2)} console.log(bobChild); // -> [{name: "Jack", age: 8, hobby: Array(2)}, [{name: "Tom", age: 1, hobby: Array(3)}] console.log(bobChild1); // -> {name: "Jack", age: 8, hobby: Array(2)} console.log(bobChild1Name); // -> Jack console.log(bobChild1Age); // -> 8 console.log(bobChild1Hobby); // -> ["video game", "football"] console.log(bobChild2Name); // -> Tom console.log(bobChild2Age); // -> 1 console.log(bobChild2Hobby1); // -> walk console.log(bobChild2Hobby2); // -> eat const { family: { child: [{ hobby: [, anneChildHobby2] }] } } = anne; console.log(anneChildHobby2); // -> sing
JSONの場合も同じ要領でできる。
const jsonData = [ { "name": "Bob", "age": 30, "country": "USA", "family": { "child": [ { "name": "Jack", "age": 8, "hobby": ["video game", "football"] }, { "name": "Tom", "age": 1, "hobby": ["walk", "eat", "sleep"] } ] } }, { "name": "Anne", "age": 25, "country": "Germany", "family": { "child": [ { "name": "Clara", "age": 3, "hobby": ["play house", "sing"] } ] } } ]; const [bob, anne] = jsonData; const { "name": bobName, "age": bobAge, "country": bobCountry, "family": bobFamily, "family": { "child": [...bobChild], "child": [bobChild1, bobChild2], "child": [{ "name": bobChild1Name, "age": bobChild1Age, "hobby": [...bobChild1Hobby] }, { "name": bobChild2Name, "age": bobChild2Age, "hobby": [bobChild2Hobby1, bobChild2Hobby2] }] } } = bob; console.log(bob); // -> {name: "Bob", age: 30, country: "USA", family: {…}} console.log(bobName); // -> Bob console.log(bobFamily); // -> {child: Array(2)} console.log(bobChild); // -> [{name: "Jack", age: 8, hobby: Array(2)}, [{name: "Tom", age: 1, hobby: Array(3)}] console.log(bobChild1); // -> {name: "Jack", age: 8, hobby: Array(2)} console.log(bobChild1Name); // -> Jack console.log(bobChild1Age); // -> 8 console.log(bobChild1Hobby); // -> ["video game", "football"] console.log(bobChild2Name); // -> Tom console.log(bobChild2Age); // -> 1 console.log(bobChild2Hobby1); // -> walk console.log(bobChild2Hobby2); // -> eat const { "family": { "child": [{ "hobby": [, anneChildHobby2] }] } } = anne; console.log(anneChildHobby2); // -> sing
まとめ
慣れないととっつきにくく感じるかもしれないが、従来の書き方よりも短い記述で済むうえに、コードの見通しもよくなるケースがあるので積極的に取り入れていきたい。
ただ、むやみに使うと逆に可読性が落ちる場合があるので注意したい。