0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

分割代入の注意点

Posted at

はじめに

スプレッド構文はオブジェクトをイミュータブルに扱いたい場面で活躍します。Reduxでは、よく使われる構文の一つかなと思います。既存のソースを見ても、Reducerを作る際にスプレッド構分で書かかれることが多いと思うので、その利用方法と注意点のまとめです。

対象読者

  • JS初学者
  • Redux初学者

##スプレッド構文とは

MDNからの引用です。

配列式や文字列などの反復可能オブジェクトを、0 個以上の引数 (関数呼び出しの場合) や要素 (配列リテラルの場合) を期待された場所で展開したり、オブジェクト式を、0 個以上のキーと値のペア (オブジェクトリテラルの場合) を期待された場所で展開したりすることができます。

MDN スプレッド構文

実際の利用方法を見てみましょう。

オブジェクトで利用する

既存のReducerの記述を見ると、Object.assign()で書かれてるものも見かけますが、以下のような書き方で置き換えできるかなと思います。


const favMusic = {
  genre: "rock",
  country: "uk"
}

// ① オブジェクトをクローンする
const clone_favMusiv = {
  ...favMusic
} // ▶︎ { genre: 'rock', country: 'uk' }

// ② オブジェクトをマージして新たなオブジェクトを生成する
const merge_favMusiv = {
  ...favMusic,
  ...{age: "90s", genre_detail: "alternative"}
} // ▶︎ { genre: 'rock', country: 'uk', age: '90s', genre_detail: 'alternative' }

// ③ プロパティを追加して新たなオブジェクトを生成する
const add_to_clone_favMusiv = {
  ...favMusic,
  age: "90s"
} // ▶︎ { genre: 'rock', country: 'uk', age: '90s' }

配列で利用する


const hobby = ["running", "game", "camp"];

// ① 配列をクローンする
const clone_hobby = [...hobby]; // ▶︎ ["running", "game", "camp"]

// ② 複数の配列をマージして新たな配列を生成する
const merge_hobby = [...hobby, ...clone_hobby]; // ▶︎ [ 'running', 'game', 'camp', 'running', 'game', 'camp' ]

// ③ 新しい要素を追加して配列を生成する
const add_to_clone_hobby = [...hobby, "fishing", "cooking"]// ▶︎ [ 'running', 'game', 'camp', 'fishing', 'cooking' ]

##スプレッド構文の注意点

① 元のオブジェクトに同名プロパティがある場合

同名プロパティを展開した場合、値は上書きされます。


const favMusic = {
  genre: "rock",
  country: "uk"
}

// ここでは、genreが上書きされてしまう
const replaceProp_favMusiv = {
  ...favMusic,
  ...{genre: "classic"}
} // ▶︎ { genre: 'classic', country: 'uk' }

② ネストしてるオブジェクト/配列

スプレッド構文は、 shallow_copyのため、以下のような場合、意図しない実装をしてしまう可能性があるので注意が必要です。ここでは、オブジェクトを例に挙げます。


const favMusicDetail = {
  genre: "rock",
  country: "uk",
  artist: {
    name: "The Beatles",
    age: "60s",
  }
}

const shallowCopy = {...favMusicDetail}
// 期待値:False
console.log("参照が異なるか検証", favMusicDetail === shallowCopy); // ▶︎ False

// 期待値:False
console.log("子オブジェクト_参照が異なるか検証", favMusicDetail.artist === shallowCopy.artist); // ▶︎ True

上記を確かめると分かるのですが、子オブジェクトは同じ参照であることが分かります。
続いて値を更新してみましょう。


// 一方のオブジェクトの値を更新してみます。
favMusicDetail.genre = "classic";
favMusicDetail.artist.age = "70s";

console.log("favMusicDetail: ", favMusicDetail, "shallowCopy: ", shallowCopy);
// 子オブジェクトは参照先が同じなので、両方とも値が更新されている
// artice.ageが書き換わってることに注目
// ⬇️
//favMusicDetail:  {
//  genre: 'classic',
//  country: 'uk',
//  artist: { name: 'The Beatles', age: '70s' }
//} shallowCopy:  {
//  genre: 'rock',
//  country: 'uk',
//  artist: { name: 'The Beatles', age: '70s' }
//}

子のオブジェクトは同じ参照なことがわかります。
そのため、ネストしているオブジェクトを扱う場合は、以下の通り、個別に分割する必要があるので注意が必要です。
以下コードを追記して確かめてみると、オブジェクトが正しくクローンされてることが分かると思います。

const cloneDetail = {
  ...favMusicDetail,
  artist: {
    ...favMusicDetail.artist, // 分割代入は、shallow_copyのため、個別に分割する必要がある。
  }
}

// 正しくコピーされてる。
favMusicDetail.artist.age = "80s";
console.log("favMusicDetail: ", favMusicDetail, "cloneDetail: ", cloneDetail);
// ⬇️
//favMusicDetail:  {
//  genre: 'classic',
//  country: 'uk',
//  artist: { name: 'The Beatles', age: '80s' }
//} cloneDetail:  {
//  genre: 'classic',
//  country: 'uk',
//  artist: { name: 'The Beatles', age: '70s' }
//}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?