差分
このページの2つのバージョン間の差分を表示します。
次のリビジョン | 前のリビジョン | ||
javascript:参照とコピー [2022/12/20 01:36] – 作成 baba | javascript:参照とコピー [2022/12/20 09:16] (現在) – [参照とコピー] baba | ||
---|---|---|---|
行 1: | 行 1: | ||
====== 参照とコピー ====== | ====== 参照とコピー ====== | ||
- | <WRAP center round important 60%> | + | インターネットで調べると、jsにおいて参照渡しとコピーがあると明言されているものが多いですが、実際にはすべて参照渡しです。参照渡しとコピーで話をしたほうが理解が容易(振る舞いを覚えやすい)ということがありますが、このページでは正しい認識(参照のみで説明)をもつことを目指します。 |
- | インターネットで調べると、jsにおいて参照渡しとコピーがあると名言されているものが多いですが、実際にはすべて参照渡しです。参照渡しとコピーで話をしたほうが理解が容易(振る舞いを覚えやすい)ということがありますが、このページでは正しい認識(参照のみで説明)をもつことを目指します。 | + | |
- | </ | + | |
+ | ===== 根本の理解 ===== | ||
まずは以下のコードを読んで実行結果を把握してください。 | まずは以下のコードを読んで実行結果を把握してください。 | ||
行 15: | 行 14: | ||
var ob = {id:2}; // obという変数がメモリ上のどこかに確保され、変数(細かくはオブジェクト型){id: | var ob = {id:2}; // obという変数がメモリ上のどこかに確保され、変数(細かくはオブジェクト型){id: | ||
oa = ob; // oaはobの参照先である{id: | oa = ob; // oaはobの参照先である{id: | ||
- | console.log(oa); | + | console.log(oa); |
</ | </ | ||
- | 長いコメントが付いていますが、よく読んで理解した上で次のコードと実行結果をよく読んでみてください。 | + | {{: |
+ | |||
+ | 長いコメントが付いていますが、よく読んで理解してください。上記のメモリ空間での話を理解しやすいように図も示しておきました。 | ||
+ | |||
+ | では次のコードと実行結果をよく読んでみてください。 | ||
<code .js> | <code .js> | ||
行 29: | 行 32: | ||
var oa = {id:1}; | var oa = {id:1}; | ||
var ob = {id:2}; | var ob = {id:2}; | ||
- | oa = ob; // oaの参照先がobの参照先、つまり{id: | + | oa = ob; // oaの参照先がobの参照先、つまり{id: |
- | ob.id = 3; // ob.id、つまり {id:2} のidの参照先が新しくメモリ上に確保された3になる。oaは{id: | + | ob.id = 3; // ob.id、つまり {id: 2} のidの参照先が新しくメモリ上に確保された3になる。oaは{id: |
- | console.log(oa); | + | console.log(oa); |
</ | </ | ||
+ | |||
+ | {{: | ||
ポイントは、最後のoaに関してob.idで変更したはずの値がoa.idにも反映されてしまっている、という点です。コメントで説明している通りですが、参照先の値が変更された為、oa.idも変更した値になっている。ということです。例えばob.idは3で、oa.idはob.idの初期値である2のままにしたかった場合は、次のようなコードになります。 | ポイントは、最後のoaに関してob.idで変更したはずの値がoa.idにも反映されてしまっている、という点です。コメントで説明している通りですが、参照先の値が変更された為、oa.idも変更した値になっている。ということです。例えばob.idは3で、oa.idはob.idの初期値である2のままにしたかった場合は、次のようなコードになります。 | ||
行 41: | 行 46: | ||
oa = Object.assign({}, | oa = Object.assign({}, | ||
ob.id = 3; | ob.id = 3; | ||
- | console.log(oa); | + | console.log(oa); |
</ | </ | ||
このようにすることで、oaの参照先をobの初期値である{id: | このようにすることで、oaの参照先をobの初期値である{id: | ||
- | インターネットに流布している「値渡しはコピー、オブジェクト私は参照」という考え方の根っこはどれも参照渡しになっていることの結果に過ぎません。変数に変数を代入する場合は、代入する変数が参照している先を代入される変数に渡しているわけです。 | + | インターネットに流布している「値渡しはコピー、オブジェクト私は参照」という考え方の根っこはどれも参照渡しになっていることの結果に過ぎません。変数に変数を代入する場合は、代入する変数が参照している先を代入される変数に渡しているわけです。ただしコピーもとのObjectのデータ構造が2層、3層と深くなっている場合、結局参照先を見に行ってしまうので、一旦JSONに変換してから改めてデータ構造を作り直すようにするのが間違いないです。 |
+ | |||
+ | <code .js> | ||
+ | var oa = {id:1}; | ||
+ | var ob = {id:2}; | ||
+ | oa = Object.assign({}, | ||
+ | ob.id = 3; | ||
+ | console.log(oa); | ||
+ | </ | ||
+ | |||
+ | ===== 練習 ===== | ||
+ | では理解ができたところで、少し練習してみましょう。 | ||
+ | <code .js> | ||
+ | var inputs = {x:1,y:2} | ||
+ | var a = inputs; | ||
+ | inputs.x = 10; | ||
+ | inputs.y = 11; | ||
+ | var b = inputs; | ||
+ | console.log(a, | ||
+ | </ | ||
+ | 上記のコードを修正して、a = {x:1,y:2}, b = {x:10, y: | ||
+ | |||
+ | 【正解】 | ||
+ | <code .js> | ||
+ | var inputs = {x:1,y:2} | ||
+ | var a = Object.assign({}, | ||
+ | inputs.x = 10; | ||
+ | inputs.y = 11; | ||
+ | var b = inputs; | ||
+ | // 後の処理を考えて、bもaと同様にObjectをコピーするようにしておくとよいでしょう。 | ||
+ | // var b = Object.assign({}, | ||
+ | console.log(a, | ||
+ | </ | ||