回答編集履歴
1
コピーメソッドを、クラスメソッドもコピーできるものに修正、参照についての説明に補足追記
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
|
-
|
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(
|
79
|
+
for(let key in obj){
|
80
|
+
|
68
|
-
|
81
|
+
// プロパティがオブジェクトなら、再起的に自身を実行して潜っていく、値なら、そのまま代入
|
82
|
+
|
69
|
-
|
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
|
-
|
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
|
以上です。
|