JavaScriptでは、変数の代入方法によって、値がどのように扱われるかが異なります。基本的に、プリミティブ型(基本型)の値とオブジェクト型の値の扱いが異なります。
プリミティブ型
プリミティブ型(例えば、number
、string
、boolean
、null
、undefined
、symbol
、bigint
)は、値のコピーが行われます。そのため、ある変数を別の変数に代入しても、元の変数の値は変更されません。
let a = 10;
let b = a; // 値のコピー
b = 20;
console.log(a); // 10
console.log(b); // 20
オブジェクト型
オブジェクト型(例えば、object
、array
、function
)は参照がコピーされます。つまり、変数が参照しているメモリ上の場所がコピーされるため、どちらの変数も同じオブジェクトを指すことになります。そのため、一方を変更すると他方も変更されます。
let obj1 = { x: 10 };
let obj2 = obj1; // 参照のコピー
obj2.x = 20;
console.log(obj1.x); // 20
console.log(obj2.x); // 20
この挙動は正常です。オブジェクト型を別の変数に代入した場合、同じオブジェクトを指すことになるため、どちらか一方で変更を加えると、もう一方にも影響が出ます。
対策
もしオブジェクトをコピーして、新しいオブジェクトとして扱いたい場合は、浅いコピーや深いコピーを行う方法があります。
- 浅いコピー:
Object.assign()
やスプレッド構文を使用
let obj1 = { x: 10 };
let obj2 = { ...obj1 }; // 浅いコピー
obj2.x = 20;
console.log(obj1.x); // 10
console.log(obj2.x); // 20
- 深いコピー:
JSON.parse(JSON.stringify())
や再帰的にコピーする関数を使用(ただし、ネストされたオブジェクトや循環参照に注意が必要)
let obj1 = { x: 10, nested: { y: 20 } };
let obj2 = JSON.parse(JSON.stringify(obj1)); // 深いコピー
obj2.nested.y = 30;
console.log(obj1.nested.y); // 20
console.log(obj2.nested.y); // 30
このようにして、オブジェクトのコピーを作成することで、元のオブジェクトへの影響を防ぐことができます。
まとめ
JavaScriptでは、変数の代入方法によって値の扱い方が異なります。理解しておくべきポイントは、プリミティブ型とオブジェクト型の二つの異なる振る舞いです。
プリミティブ型
- 定義: プリミティブ型には
number
、string
、boolean
、null
、undefined
、symbol
、bigint
が含まれます。 - 動作: プリミティブ型の変数を別の変数に代入すると、値のコピーが行われます。これにより、代入後に新しい変数を変更しても元の変数には影響しません。
オブジェクト型
- 定義: オブジェクト型には
object
、array
、function
などが含まれます。 - 動作: オブジェクト型の変数を別の変数に代入すると、参照のコピーが行われます。これにより、代入先の変数を変更すると元の変数も影響を受けます。これは両方の変数が同じメモリ上のオブジェクトを指しているためです。
オブジェクト型のコピー方法
- 浅いコピー:
Object.assign()
やスプレッド構文{ ...obj }
を使用して、新しいオブジェクトを作成します。この方法は、オブジェクトの最上位のプロパティだけをコピーします。 - 深いコピー:
JSON.parse(JSON.stringify())
を使うことで、オブジェクト全体を再帰的にコピーします。注意点として、循環参照があるオブジェクトには使用できません。また、関数やundefined
などはコピーされません。
これらの知識を活用することで、JavaScriptでの変数操作をより効果的に行えるようになります。特に、オブジェクトの代入やコピーを扱う際に注意が必要です。