javascript:参照とコピー

差分

このページの2つのバージョン間の差分を表示します。

この比較画面へのリンク

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