はじめに
こんにちは、イメージ・マジックの安藤です。
社会人歴は2年目に突入し、入社して1ヶ月ほどが過ぎました.
日々バグ対応を行っているのですが、弊社のシステムに関する私の理解がまだ浅いので苦戦することも多々あり、そこが仕事の面白みかなともまた思っている次第です。
今回はコードを書く上でのワンポイントとしてImmutableという概念について少し触れればと思います。
なお、以下サンプルコードはJavaScriptで記載します。
Immutableとは
ある値がImmutableであるとはどういうことでしょうか?
この記事では、「ある値の状態が変わることがない」ということをImmutableとしたいと思います。
普通に考えると、Immutable=不変なので値が変わらないということから定数のようなものを思い浮かべるかもしれませんが、その違いとは何でしょうか。
まずは単純に数字同士の足し算を考えてみましょう。
数字同士の足し算はすべてImmutableになり、以下の例ではnum1やnum2はconstなので直接書き換えることもできないためこれらの値の状態が変わることはありません。
const num1 = 1; const num2 = 3; const num3 = num1 + num2; console.log(num1, num2, num3); // 1 3 4
では、値の状態が変わる(mutable)場合の例を見てみましょう。
以下ではarrはconstとなっていますが、sort関数で昇順にソートすることでarr自体が変更されていることがわかるでしょうか。
const arr = [1, 3, 2, 5, 4]; arr.sort((a, b) => a - b); console.log(arr); // [1, 2, 3, 4, 5]
何故このようなことが起こるのかというと、少し難しい話になりますが、constはオブジェクトのインスタンスが変わらないことしか保証しないからです。
上記の例ではarrはArrayクラスのインスタンスになっており、オブジェクトの内部で状態が変更されています。
そして、arrが見ているインスタンス自体は変更されていないため、arrがconstであるかどうかに関わらず値の状態を変更することができてしまいます。
余談ですが、sortのような呼び出したオブジェクト自体が変化するメソッドを破壊的メソッドと呼びます。
なお、同じArrayクラスでも以下のように破壊的でないものもあります。JavaScriptに限らないですが、自分の使おうとしているメソッドが破壊的か否かはきちんと確認するべきでしょう。
const arr = [1, 2, 3, 4, 5]; const added = arr.map(n => n + 1); console.log(arr, added); // [1, 2, 3, 4, 5] [2, 3, 4, 5, 6]
最後に、Immutableな配列への要素追加とmutableな配列への要素追加の対比の例を載せておきます。
const arr = [1, 2, 3, 4]; const arr2 = arr.concat(5); // immutable add console.log(arr, arr2); // [1, 2, 3, 4] [1, 2, 3, 4, 5] arr.push(5); // mutable add console.log(arr, arr2); // [1, 2, 3, 4, 5] [1, 2, 3, 4, 5]
Immutableであるメリットとは
ここまでImmutableとは何かということに触れてきましたが、Immutableであることのメリットに触れていきたいと思います。
Immutableであることの最大のメリットはオブジェクトの破壊的変更を気にする必要がなくなるという点に尽きます。これはプログラムを書いていくうえで想定外の変更が起きにくくなり、バグを抑制することができるということでもあります。
また、Immutableを適切に意識することでプログラム上でどの値がどのように変更されていくのかが追いやすくなるという効果もあるでしょう。
Immutabeで注意すべき点
Immutableにしようとする値の状態が頻繁に変更される場合や変更可能なデータを多く持っている場合、Immutableは適切でないことが多いため注意が必要です。
また、非破壊的メソッドを使っているとメソッドチェーンを繋げやすくなりますが、過剰なメソッドチェーンは可読性を下げることになるので注意しましょう。