当サイトは、アフィリエイト広告を利用しています
...hogeの形で下記配列やオブジェクトの要素を展開して扱うことができる構文。
スプレッド構文を使うことで新しい配列を作ったり、配列をマージしたり
分割したりすることができる。
// 配列を定義const array1 = [1,2,3]const array2 = [4,5,6,7]// arrayを展開して新しい配列を作成const newArray = [0,...array1,99]console.log(newArray)// array1とarray2を展開、マージするconst margeArray = [...array1,...array2]console.log(margeArray)// 分割代入とレスト構文で配列を分割するconst [val1,val2,...rest] = margeArrayconsole.log(val1,val2,rest)
オブジェクトで使う場合はプロパティの追加やオブジェクトのマージができる。
スプレッド構文は後に書いた方で上書きされるので注意が必要。
// 空オブジェクトの型type EmptyObject = { [key: string]: any };// オブジェクトを定義const user:EmptyObject = { id: 1, name: "hogehoge" }const userDetail:EmptyObject = { address: "xxx", weight:60 }// 新規プロパティを追加するconst user2 = {...user,age:21}console.log(user2)// 結果//{id: 1, name: "hogehoge", age: 21}// オブジェクトをマージするconst margeUser = {...user,...userDetail}console.log(margeUser)// 結果// {id: 1, name: "hogehoge", address: "xxx", weight: 60}// 同じプロパティは上書きされるlet user3 = {...user2,age:99}console.log(user3)// 結果// {id: 1, name: "hogehoge", age: 99}// 順番を入れ替えてしますと設定した値も後ろに設定した値で// 上書きされるuser3 = {age:99,...user2}console.log(user3)// 結果// {age: 21, id: 1, name: "hogehoge"}
スプレッド構文はシャローコピーなので
ネストしている配列やオブジェクトを扱う場合は注意する
// userタイプを定義type User = {id:number, detail: {name:string, age:number}};// オブジェクトを定義const user:User = {id: 1, detail: {name: 'hoge', age: 29}};// スプレッド構文でコピー(シャローコピー)const copyUser = {...user}// コピー元のnameを変更user.detail.name = 'xxxxxxxxxx'// コピーを出力console.log(copyUser);// ログ// id: 1// detail:{// name: "xxxxxxxxxx"// age: 29// }
ネストされている場合は子はシャローコピーのためコピー元と同じ参照になってしまうため
コピー元のネスト部分を変更した場合、コピー先もかわってしまう。
ディープコピーしたい場合はスプレッド構文ではなく、下記の二つのどちらかでする
// userタイプを定義type User = {id:number, detail: {name:string, age:number}};// オブジェクトを定義const user:User = {id: 1, detail: {name: 'hoge', age: 29}};// JSONメソッドでコピー(ディープコピー)const copyUser = JSON.parse(JSON.stringify(user))// コピー元のnameを変更user.detail.name = 'xxxxxxxxxx'// コピーを出力console.log(copyUser);// ログ// id: 1// detail: {// name: "hoge"// age: 29// }
コピー元が変わっても更新されていないが、注意としてはJSON.stringifyはオブジェクトを文字列に
変換してから再度、オブジェクトに戻すという手順を取っているため
文字列に変換できないundefinedや関数があった場合は情報が落ちる
// userタイプを定義type User = {id: number;detail: { name: string; age?: number; func: (param: string) => string };};// 関数を定義const func = (val: string) => `関数 : ${val}`;// オブジェクトを定義// ネストしたオブジェクトにundefinedと関数を設定するconst user: User = {id: 1,detail: { name: "hoge", age: undefined, func: func }};// JSONメソッドでコピー(ディープコピー)const copyUser = JSON.parse(JSON.stringify(user));// コピー元のnameを変更user.detail.name = "xxxxxxxxxx";// コピーを出力console.log(copyUser);// ログ// id: 1// detail: {// name: "hoge"// }
関数とundefinedであるプロパティはコピーできていない
lodashのcloneDeepを使えばディープコピーをすることができる
import * as _ from "lodash";// userタイプを定義type User = {id: number;detail: { name: string; age?: number; func: (param: string) => string };};// 関数を定義const func = (val: string) => `関数 : ${val}`;// オブジェクトを定義// ネストしたオブジェクトにundefinedと関数を設定するconst user: User = {id: 1,detail: { name: "hoge", age: undefined, func: func }};// lodashメソッドでコピー(ディープコピー)const copyUser = _.cloneDeep(user);// コピー元のnameを変更user.detail.name = "xxxxxxxxxx";// コピーを出力console.log(copyUser);// ログ// id: 1// detail: {// name: "hoge"// age: undefined// func: ƒ func() {}// }
関数とundefinedであるプロパティもコピーできている
下記の記事を参考してまとめさせて頂きました。
JSのスプレッド構文を理解する
【JavaScript】スプレッド構文の便利な使い方まとめ