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 1 year has passed since last update.

【JavaScript】スプレッド構文 シャローコピーの落とし穴

Posted at

スプレッド構文がシャローコピーであることをしっかり理解できていなかったために業務中に落とし穴にはまりました。備忘録としてまとめます。

スプレッド構文とは?

スプレッド構文は、配列やオブジェクトの中身を展開する事ができます。

const numbers1 = [1, 2, 3]
const numbers2 = [...numbers1, 4, 5]
console.log(numbers2)

上記の実行結果は、
スクリーンショット 2023-02-11 17.47.55.png
となり、

const fruites1 = {
    apple: 'りんご',
    banana: 'ばなな',
    grape: 'ぶどう'
}
const fruites2 = {
    ...fruites1,
    lemon: 'レモン',
    orange: 'オレンジ'
}
console.log(fruites2)

上記の実行結果は、
スクリーンショット 2023-02-11 17.53.13.png
となります。

※※※余談※※※
オブジェクトにおいて、プロパティ名が重複している場合は上書きされます。

const fruites1 = {
    apple: 'りんご',
    banana: 'ばなな',
    grape: 'ぶどう'
}
const fruites2 = {
    ...fruites1,
    apple: 'apple',
    orange: 'オレンジ'
}
//fruites2で、fruites1を展開した後、fruites1のプロパティとして存在するappleを上書き
console.log(fruites2)

実行結果はスクリーンショット 2023-02-11 17.55.39.png※※※余談終わり※※※

スプレッド構文はシャローコピー

本題です。
まず、以下の例において、実行結果は何になるでしょうか?

const numbers1 = [1, 2, 3]
const numbers2 = [...numbers1]
numbers2.push(4)

console.log(numbers1)
console.log(numbers2)

答えは、
スクリーンショット 2023-02-11 18.21.07.png
となります。
次にオブジェクトの場合です。実行結果は何になるでしょうか?

const fruites1 = {
    apple: 'りんご',
    banana: 'ばなな',
    orange: 'オレンジ'
}
const fruites2 = {...fruites1}
fruites2['grape'] = 'ぶどう'

console.log(fruites1)
console.log(fruites2)

答えは、スクリーンショット 2023-02-11 18.22.44.png
となります。

この二つに共通して言えることは、スプレッド構文を用いて新しいオブジェクトを作成した場合、新しく作成したオブジェクトに変更を加えても元のオブジェクトには影響を与えない、ということです。
ただし、どんな状況でもこの考え方が適用できるかというと、そうではありません。
次の例をご覧ください。

const numbers1 = [
    [1],
    [2],
    [3]
]
const numbers2 = [...numbers1]
numbers2[0].push(2)

console.log(numbers1)
console.log(numbers2)

この実行結果はどうなるでしょうか?

//number1 => [[1],[2],[3]]
//numbers => [[1, 2],[2], [3]]

となると思ってしまいそうすが、、、、こうはなりません!!
以下のようになります。
スクリーンショット 2023-02-11 18.42.22.png

そうです、元の配列(fruites1)の内容が変更されてしまっています
次にオブジェクトの場合も確認します。


const fruites1 = {
    fruites: {
      apple: 'りんご',
      banana: 'ばなな',
      orange: 'オレンジ'
    },
    vegitables: {
        tomato: 'トマト',
        eggplant: 'おなす'
    }
}
const fruites2 = {...fruites1}
fruites2['fruites']['grape'] = 'ぶどう'

console.log(fruites1)
console.log(fruites2)

実行結果は以下になります。
スクリーンショット 2023-02-11 18.44.41.png
こちらも配列と同様、元のオブジェクトが変更されてしまっています。
スプレッド構文を用いてオブジェクトや配列などを展開した場合、一階層の深さまでしかコピーされず、二階層以上は元のオブジェクトを参照します(シャローコピー)。 

おわりに

今回取り上げたのはスプレッド構文でしたが、他にもオブジェクトを変更不可にするObject.freeze()もジャローコピーですし、シャローコピーについてはしっかり理解していないと思わぬバグの原因になってしまうので、今後も気を付けていきたいと思います。

参考文献:mdn web docs スプレッド構文

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?