🙆

代入にも罠があった

に公開1

関数の引数だとか、変数への代入だとかは頻繁にやるけど、実は2種類に分けることができる。
それは、値を入れるか、参照を入れるかの二つだ。まあ例を見ればわかる

const a = 10;
const b = a;
const b = 20;
console.log(a,b)
//10,20
const a = {text:"hello"}
const b = a;
b.text = "how are you?"
console.log(a,b)
//how are you? how are you?

これらの条件だが、オブジェクトかプリミティブかによって分岐する。
値がオブジェクトな変数を、ほかの変数に代入すると、それは参照渡しの状態になる。
値がプリミティブ型なら、それは値渡しになる。
ちなみに、オブジェクト変数を代入し、参照渡しになっても、ほかのオブジェクトを代入すれば、それは解除される。

let a = {a:1,};
let b = a;
b = {a:2};
console.log(a.a,b.a);
//1,2

オブジェクトを値渡しでコピーするには、浅いコピーと深いコピーの2通りのやり方がある。
浅いコピー

const a = {
	shallow:1,
	nest:{c:2}
}
const b = {...a}
b.shallow=10
b.nest.c=3;
console.log(a.shallow,b.shallow);
//1,10 独立してる
console.log(a.nest.c,b.nest.c);
//3,3 参照が渡されてて共有

深いコピー(めんどいので、多用するならライブラリとか使おう)

const a = {
	shallow:1,
	nest:{c:2}
}
const b = JSON.parse(JSON.stringify(a));
b.shallow=10
b.nest.c=3;
console.log(a.shallow,b.shallow);
//1,10 独立してる
console.log(a.nest.c,b.nest.c);
//2,3 ネストされた部分も独立

ただし、深いコピーは容量を食うので、必要な場合のみに使用

Discussion

junerjuner

値がオブジェクトな変数を、ほかの変数に代入すると、それは参照渡しの状態になる。

インスタンスが共有されているだけなので、それは参照渡しではないのではないでしょうか?

※参照渡しが共有するのは変数であって オブジェクトではないです。

もしも参照渡しの様な変数の参照を渡す挙動を確認したい場合は import した変数を export 元で 代入するとその動作を確認することができます。


深いコピー(めんどいので、多用するならライブラリとか使おう)

structuredClone おすすめします。

https://developer.mozilla.org/ja/docs/Web/API/Window/structuredClone