Edited at

ミュータブルな型とイミュータブルな型の相違を知ろう


変数について

変数とは、もちろん値を格納する領域のことですね。変数名と値を結び付けることを「変数に値を代入する」などと言います。

var num = 3; // (1)数値型

var array = [1, 3, 4]; // (2)Arrayオブジェクト(配列)

上記の(1)はプリミティブ型である数値の「3」を変数numに、(2)は3つの要素を持つArrayオブジェクト(配列)を変数arrayに代入しています。

どちらも、変数には値そのものが格納されるというイメージでとらえないでください。変数の場所を指し示すリファレンスと呼ばれる値が格納される考えるとよいでしょう。

h1.png

あるいは変数名は値に付けられたタグのようなイメージでとらえてもかまいません。

h2.png

このことを頭に入れておくと、変数を別の変数に代入した場合の動作がわかりやすくなります。次の例を見てみましょう。

var a = 1;

var b = a; // (1)
a = a + 2; // (2) a:3、b:1

この場合、(1)の段階では変数aも変数bも「1」という同じ値を指し示しています。

h3.png

(2)では変数aは新たに「3」という値を指し示しますが、変数bは「1」のままです。

h4.png

Arrayオブジェクトなどのオブジェクト型を変数に代入した場合も考え方は同じです。

var a1 = [1, 3, 4]:

var a2 = a1; // (1)
var a1 = [5, 6]; // (2 )a1: [5, 6]、a2:[1, 3, 4]

(1)の段階では変数a1、a2ともに「 [1, 3, 4]」を指し示していますが、(2)の段階ではa1とa2は異なる配列を指し示しています。


ミュータブルとイミュータブル

さて、データ型にはミュータブル(変更可)とイミュータブル(変更不可)という分け方もあります。プリミティブ型はイミュータブルです。また、StringやNumberといったラッパーオブジェクトもイミュータブルです。それに対してArrayオブジェクトやObjectオブジェクト、Dateオブジェクトなどはミュータブルなオブジェクトです。

ここで、数値型などは変数に演算を行って、また同じ変数に格納できるのでミュータブルなのでは?と考える方もいるでしょう。

var num = 1;

num = num + 3; // numの値は4

これは「1」という数値を変更しているわけではありません。「num + 3」で新たに「4」という数値を生成してそのリファレンスを変数numに再代入しているのです。あるいは「4」という数値に「num」というラベルを設定しなおしていると考えてもいいでしょう。

文字列(およびStringオブジェクト)もイミュータブルな型です。

var str = "Hello"

str = str + " World" // (1)"Hello World"

上記の例では"Hello"という文字列を変更しているわけではありません。(1)では変数strと" World"を連結して新たな文字列「"Hello World"」を生成し変数strに代入しています。

また、次のように文字列内の文字に別の文字を代入しても反映されません(エラーにならず無視されます)。

var str = 'Hello';

// 2番目の文字に'a'を代入すると...
str[1] = 'a';
console.log(str); // 'Hello'のまま

一方ミュータブルな型であるArrayオブジェクトは、後から要素を変更できます。

var array = [1, 3, 4];

array[0] = 5; // [5, 3, 4]

別の例として、Dateオブジェクトもミュータブルな型ですので、後から値を変更できます。

var theDate = new Date();

theDate.setFullYear(1959); // 年を1959に変更