回答編集履歴
4
シャローコピーだとstateが壊れちゃって駄目だったので再修正
answer
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
```JavaScript
|
6
6
|
// この方法は楽だけど、正規表現やDateみたいなインスタンスが来ると困る
|
7
|
-
JSON.
|
7
|
+
JSON.parse(JSON.stringify(state));
|
8
8
|
|
9
9
|
// これは駄目
|
10
10
|
var hoge = {a: [1, 2, 3], b: 123};
|
@@ -22,7 +22,7 @@
|
|
22
22
|
```
|
23
23
|
|
24
24
|
再帰呼び出しでコツコツ作っていくしかない。
|
25
|
-
結論、`JSON.
|
25
|
+
結論、`JSON.parse(JSON.stringify(state))`で解決出来なければライブラリ使うべき。
|
26
26
|
|
27
27
|
> (2)forEachは値をreturn出来ないが、forEachを使わず副作用の無いように書くにはどうしたら良いのか?
|
28
28
|
|
@@ -37,8 +37,12 @@
|
|
37
37
|
JSでは`[].reduce`というプロトタイプメソッドがあるのでそれを利用する。
|
38
38
|
|
39
39
|
`to_state`の部分は関数として切り出せたから楽にテスト出来るね。
|
40
|
-
しかし
|
40
|
+
しかしpushが破壊的なメソッドだからどう扱うかがJSの課題だね。
|
41
|
+
ディープコピーをしないとすぐにstateが壊れる。
|
41
42
|
|
43
|
+
草案だとmergeの最初でシャローコピーしてたけどそれじゃ駄目で、
|
44
|
+
ディープコピーが必要になったので`clone`というメソッドを作って入り口で作って対応した。
|
45
|
+
|
42
46
|
```JavaScript
|
43
47
|
const payload = [
|
44
48
|
{id: '001', score: 100},
|
@@ -58,16 +62,16 @@
|
|
58
62
|
]
|
59
63
|
}
|
60
64
|
|
65
|
+
const clone = (it) => JSON.parse(JSON.stringify(it))
|
61
|
-
const
|
66
|
+
const merge = (data, it) => {
|
62
|
-
let data = Object.assign({}, state);
|
63
67
|
if (data[it.id] == null) data[it.id] = [];
|
64
68
|
data[it.id].push(it);
|
65
69
|
return data;
|
66
70
|
}
|
67
71
|
|
68
|
-
console.log(payload.reduce(
|
72
|
+
console.log(payload.reduce(merge, clone(state)));
|
69
73
|
// Object {100: Array(2), 001: Array(4), 010: Array(2)}
|
70
74
|
|
71
75
|
console.log(state);
|
72
|
-
// Object {001: Array(
|
76
|
+
// Object {001: Array(2), 010: Array(2)}
|
73
77
|
```
|
3
あれ、1と2は違うじゃん。というわけで1も回答
answer
CHANGED
@@ -1,3 +1,29 @@
|
|
1
|
+
> (1)Deep Copyするには?(ライブラリで解決する方法は既に把握済みですが、ライブラリを使わない場合はどう書くのか?
|
2
|
+
|
3
|
+
さりげに難問
|
4
|
+
|
5
|
+
```JavaScript
|
6
|
+
// この方法は楽だけど、正規表現やDateみたいなインスタンスが来ると困る
|
7
|
+
JSON.stringify(JSON.parse(state));
|
8
|
+
|
9
|
+
// これは駄目
|
10
|
+
var hoge = {a: [1, 2, 3], b: 123};
|
11
|
+
var piko = Object.entries(hoge).reduce((a, it) => {
|
12
|
+
a[it[0]] = it[1];
|
13
|
+
return a;
|
14
|
+
}. {});
|
15
|
+
piko.a.push(5); // こんな風に破壊的な修正を加えると…
|
16
|
+
|
17
|
+
console.log(hoge);
|
18
|
+
// {a: [1, 2, 3, 5], b: 123} ←配列の参照が残ってるのでこっちも変更されてしまう
|
19
|
+
|
20
|
+
console.log(piko);
|
21
|
+
// {a: [1, 2, 3, 5], b: 123}
|
22
|
+
```
|
23
|
+
|
24
|
+
再帰呼び出しでコツコツ作っていくしかない。
|
25
|
+
結論、`JSON.stringify(JSON.parse(state))`で解決出来なければライブラリ使うべき。
|
26
|
+
|
1
27
|
> (2)forEachは値をreturn出来ないが、forEachを使わず副作用の無いように書くにはどうしたら良いのか?
|
2
28
|
|
3
29
|
関数型プログラミングには`map`があって、JSにも`[].map`が用意されている。
|
@@ -7,8 +33,6 @@
|
|
7
33
|
`forEach`(もしくはeach)は順番に実行するという意味を持つ。
|
8
34
|
Ajaxを飛ばすとか、console.logで出力するとか、副作用のあるものをバシバシ実行していくためのもの。
|
9
35
|
|
10
|
-
> (1)Deep Copyするには?(ライブラリで解決する方法は既に把握済みですが、ライブラリを使わない場合はどう書くのか?
|
11
|
-
|
12
36
|
こういった処理は関数的に解決するなら畳み込み!
|
13
37
|
JSでは`[].reduce`というプロトタイプメソッドがあるのでそれを利用する。
|
14
38
|
|
2
constしたdataにpushはイケてないのでletに修正
answer
CHANGED
@@ -13,7 +13,7 @@
|
|
13
13
|
JSでは`[].reduce`というプロトタイプメソッドがあるのでそれを利用する。
|
14
14
|
|
15
15
|
`to_state`の部分は関数として切り出せたから楽にテスト出来るね。
|
16
|
-
しかし、pushが副作用のある
|
16
|
+
しかし、pushが副作用のある破壊的メソッドだから、毎回シャローコピーする重い処理になったけど、これが関数型プログラミング的にはあるべき姿だと思う。
|
17
17
|
|
18
18
|
```JavaScript
|
19
19
|
const payload = [
|
@@ -35,7 +35,7 @@
|
|
35
35
|
}
|
36
36
|
|
37
37
|
const to_state = (state, it) => {
|
38
|
-
|
38
|
+
let data = Object.assign({}, state);
|
39
39
|
if (data[it.id] == null) data[it.id] = [];
|
40
40
|
data[it.id].push(it);
|
41
41
|
return data;
|
1
副作用があったので修正
answer
CHANGED
@@ -12,9 +12,8 @@
|
|
12
12
|
こういった処理は関数的に解決するなら畳み込み!
|
13
13
|
JSでは`[].reduce`というプロトタイプメソッドがあるのでそれを利用する。
|
14
14
|
|
15
|
-
速度はthink49さんが出したようなfor文を使うやり方にかないっこないんだけど、
|
16
15
|
`to_state`の部分は関数として切り出せたから楽にテスト出来るね。
|
17
|
-
|
16
|
+
しかし、pushが副作用のあるプロトタイプメソッドでイケてないので、毎回シャローコピーする重い処理になったけど、これが関数型プログラミング的にはあるべき姿だと思う。
|
18
17
|
|
19
18
|
```JavaScript
|
20
19
|
const payload = [
|
@@ -24,12 +23,27 @@
|
|
24
23
|
{id: '100', score: 482}
|
25
24
|
];
|
26
25
|
|
26
|
+
const state = {
|
27
|
+
'001': [
|
28
|
+
{id: '001', score: 142},
|
29
|
+
{id: '001', score: 112}
|
30
|
+
],
|
31
|
+
'010': [
|
32
|
+
{id: '010', score: 142},
|
33
|
+
{id: '010', score: 112}
|
34
|
+
]
|
35
|
+
}
|
36
|
+
|
27
37
|
const to_state = (state, it) => {
|
38
|
+
const data = Object.assign({}, state);
|
28
|
-
if (
|
39
|
+
if (data[it.id] == null) data[it.id] = [];
|
29
|
-
|
40
|
+
data[it.id].push(it);
|
30
|
-
return
|
41
|
+
return data;
|
31
42
|
}
|
32
43
|
|
33
|
-
console.log(payload.reduce(to_state,
|
44
|
+
console.log(payload.reduce(to_state, state));
|
45
|
+
// Object {100: Array(2), 001: Array(4), 010: Array(2)}
|
46
|
+
|
47
|
+
console.log(state);
|
34
|
-
// Object {
|
48
|
+
// Object {001: Array(4), 010: Array(2)}
|
35
49
|
```
|