回答編集履歴

1

コピーメソッドを、クラスメソッドもコピーできるものに修正、参照についての説明に補足追記

2020/02/07 03:33

投稿

miyabi_pudding
miyabi_pudding

スコア9528

test CHANGED
@@ -4,6 +4,8 @@
4
4
 
5
5
  を参考に、ディープコピーメソッドを作った上で、
6
6
 
7
+ (上記を発展させ、クラスメソッド(prototype定義のメソッドも)含めてコピーできるようにしている)
8
+
7
9
  下記でいかがでしょうか。
8
10
 
9
11
 
@@ -62,19 +64,23 @@
62
64
 
63
65
  const deepClone = obj => {
64
66
 
65
- let r = {}
67
+ const r = (() => {
68
+
66
-
69
+ // 一応、余計な処理をいれないために、クラス名がObjectか、Arrayだったらそのまま、配列かオブジェクトかを返す
70
+
71
+ if (obj.constructor.name === 'Array' || obj.constructor.name === 'Object') return Array.isArray(obj) : [] : {};
72
+
73
+ // クラス名が上記以外なら、(クラス、prototypeがユーザー定義)Object.createをうまく使って、新しくインスタンスを生成して返す
74
+
75
+ return Object.create(obj.constructor.prototype);
76
+
77
+ })();
78
+
67
- for(var name in obj){
79
+ for(let key in obj){
80
+
68
-
81
+ // プロパティがオブジェクトなら、再起的に自身を実行して潜っていく、値なら、そのまま代入
82
+
69
- if(typeof obj[name] === 'object'){
83
+ r[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
70
-
71
- r[name] = deepClone(obj[name])
72
-
73
- } else {
74
-
75
- r[name] = obj[name]
76
-
77
- }
78
84
 
79
85
  }
80
86
 
@@ -200,11 +206,13 @@
200
206
 
201
207
  maisumakunさんがおっしゃるとおり、Object.createは、ディープコピーを生成するものではないので、改めて、ディープコピーをさせるメソッドを用意する必要があるのでしょう。
202
208
 
209
+ (Object.createは、第一引数のオブジェクトを、"prototype"として、新たにオブジェクトを生成するので、コピーメソッドの中でうまく使えば、完全に同クラスからの別参照インスタンスオブジェクトとなる)
210
+
203
211
 
204
212
 
205
213
  さて、余談になりますが、**JavaScriptには、値渡しも参照渡しも存在しません**。
206
214
 
207
- あくまで、変数は、**メモリに格納された値に対する参照**にすぎません。
215
+ あくまで、変数は、**メモリに格納された値、またはオブジェクトに対する参照**にすぎません。
208
216
 
209
217
  ```javascript
210
218
 
@@ -228,6 +236,8 @@
228
236
 
229
237
  ただし、**メモリに格納された同じオブジェクト自体を参照**しているので、`b`によって、プロパティの値を変えると、同じオブジェクトを参照している`a`の方も変化があったように見えます。
230
238
 
239
+ (各プロパティもまた、値に対する参照のため。オブジェクトは、参照をプロパティとして複数保持できるもの)
240
+
231
241
  よって、下記の場合は、`a`の変化を`b`でさせることはできなくなります。
232
242
 
233
243
 
@@ -236,7 +246,9 @@
236
246
 
237
247
  const a = {value: 15};
238
248
 
239
- const b = a;
249
+ let b = a;
250
+
251
+ // bは、新たに生成されたオブジェクトの参照となるため、aとは参照元さえも変わってしまう
240
252
 
241
253
  b = {value: 15};
242
254
 
@@ -248,4 +260,50 @@
248
260
 
249
261
 
250
262
 
263
+ オブジェクトと同様に、値に対しても同じ参照の挙動となります。
264
+
265
+
266
+
267
+ ```javascript
268
+
269
+ const a = 15;
270
+
271
+ let b = a; // bは、同じ参照元の15という値の参照となる
272
+
273
+ b = 20; // bは、新たな値20の参照となる
274
+
275
+
276
+
277
+ console.log(a); // 15
278
+
279
+ ```
280
+
281
+
282
+
283
+ ```javascript
284
+
285
+ const a = 15;
286
+
287
+ let b = a; // bは、同じ参照元の15という値の参照となる
288
+
289
+ // だが、オブジェクトと違い、裸の値であるため、どう代入し直しても、新しい値が生成される。(上記の通り新しいオブジェクトの代入は新たにメモリに格納されるので、裸の値と参照の挙動自体は同じ)
290
+
291
+ b = 15; // bは、値的には同じでも、参照元が変わってしまう。
292
+
293
+
294
+
295
+ console.log(a); // 15
296
+
297
+ ```
298
+
299
+
300
+
301
+ つまり、変数に対して、値を渡している、参照を渡しているのではなく、
302
+
303
+ 常に変数は、**値(オブジェクト)に対しての参照そのもの**となります。
304
+
305
+ 値が入っている、参照が入っている、それを渡している、ではないというわけです。
306
+
307
+
308
+
251
309
  以上です。