皆さん、シャローコピーって聞いたことありますか?
自分は聞いたことあるけど、
「ふーん、そんなものあるんだ🤫(鼻ホジ)」
「予期せぬところを変更してくるバグの原因になるやつね😠」
ぐらいの認識でした。
今回はそんな認識が変わり、シャローコピーを考えた人天才じゃね?と思うようになりました。(デメリットについてはまだ把握不足なので記事にできません)
記事がいいなと思ったらtwitterのフォローもお待ちしております‼
https://twitter.com/takeshi_program
はじめに
本記事は以下の読者様が対象です。
-
プログラミング初心者
-
コードをリーダブルにしたい人
先に結論
- シャローコピーを使うことで、コードがリーダブルになる。
背景
私は自作の集計関数を作っていました。
コードを書いた直後は「なんて綺麗なコードだろう」と自画自賛していました。🥺
しかし…
1日経って見直すと、「このコード読むの疲れるわ😡」となってしまいました。
今まで書いたコード全部がそんな感じだったんですね…
以下が自分の書いたコードの一部です。
/* this.originArray_dには以下のものが入っている
[ 2021-03-01T15:00:00.000Z],
[ 2021-03-01T15:00:00.000Z],
[ 2021-03-01T15:00:00.000Z],
[ 2021-03-01T15:00:00.000Z],
[ 2021-03-01T15:00:00.000Z]
*/
/*this.countingAraayには以下のものが入っている
[ 2021-03-01T15:00:00.000Z, 0 ],
[ 2021-03-02T15:00:00.000Z, 0 ],
[ 2021-03-03T15:00:00.000Z, 0 ],
[ 2021-03-04T15:00:00.000Z, 0 ],
[ 2021-03-05T15:00:00.000Z, 0 ],
[ 2021-03-06T15:00:00.000Z, 0 ]
*/
aggregate () {
this.originArray_d.forEach((targetCSVRecord) => {
const targetDate = targetCSVRecord[0]
const targetIndex = this.selectCountUpIndex(this.countingArray, 0, targetDate)
// selectCountUpIndexは自作関数で「countingArray」の「0番目の要素」と「countingDate」が一緒のレコードのインデックス番号を取得する関数
const beforeCount = this.countingArray[targetIndex][1]
const countingArrayDate = this.countingArray[targetIndex][0]
this.countingArray.splice(targetIndex, 1, [countingArrayDate, beforeCount + 1]) //指定の配列を別の配列で置き換える操作
})
return this.countingArray
}
なんかインデックスって言葉がめっちゃ出てきてませんか?
このインデックスに何が入っているかというと、
「配列から検索して適合したレコードの番号」が入っています。
で、その取得したインデックス番号を使って、配列の中身を変えます。
このインデックスという言葉がコードを読みづらくさせている原因だと考え色々と対策を探した結果「シャローコピー」に出会いました。
シャローコピーについて
シャローコピーとは浅いコピーとも言われ、ディープコピーと対になるものです。
例えばaをbにシャロコピーした場合
const a = [1,2,3]
const b = a
b[0] = 100
// a=[100,2,3]
// b=[100,2,3]
となり、bを変えるとaの中身も変わってしまうのです。(*プリミティブ型はシャローコピーになりません)
これはaにはいている「どこにアクセスするか」(参照)という情報をbに渡しているからです。詳しくはこちらをご覧ください。
https://developer.mozilla.org/ja/docs/Glossary/Shallow_copy
シャローコピーは予期せぬバグの危険がある反面、コードを直感的に操作させてくれるメリットがあると私は考えます。
シャローコピーを把握した上でリファクタリングした結果
シャローコピーを把握した上でリファクタリングしてみた結果が以下です。
/* this.originArray_dには以下のものが入っている
[ 2021-03-01T15:00:00.000Z],
[ 2021-03-01T15:00:00.000Z],
[ 2021-03-01T15:00:00.000Z],
[ 2021-03-01T15:00:00.000Z],
[ 2021-03-01T15:00:00.000Z]
*/
/*this.countingAraayには以下のものが入っている
[ 2021-03-01T15:00:00.000Z, 0 ],
[ 2021-03-02T15:00:00.000Z, 0 ],
[ 2021-03-03T15:00:00.000Z, 0 ],
[ 2021-03-04T15:00:00.000Z, 0 ],
[ 2021-03-05T15:00:00.000Z, 0 ],
[ 2021-03-06T15:00:00.000Z, 0 ]
*/
aggregate () {
this.originArray_d.forEach((targetCSVRecord) => {
const countingDate = targetCSVRecord[0]
const countingRecord = this.selectCountUpRecord(this.countingArray, 0, countingDate)
// selectCountUpRecordは自作関数で「countingArray」の「0番目の要素」と「countingDate」が一緒のレコードを取得しなさいという関数です。
countingRecord[1] += 1
})
return this.countingArray
}
はい、すごくコードが短くなりました。
それに直感的になりました。
今年初めての感動です😭
おわりに
例題のコードは全体の一部で、その中でもコード量が少ないものを抜粋してます。
この変更前のコードが30行も続けばどうでしょうか?
また他のメソッドでも使われていたら…
自分のコードはそのような状態でした。😇
ずっとインデックス番号に何が入っているのか覚えておく必要があり、読むのがとても苦痛で…🤮
だけどシャローコピーにより、コードが直感的になり救われました。🥹
是非シャロコピーを嫌わないで、頼れる味方だと思って使用してください❗️❗️
また発見があれば記事にしたいと思います。
ありがとうございました。👍