質問するログイン新規登録

回答編集履歴

4

シャローコピーだとstateが壊れちゃって駄目だったので再修正

2017/08/25 01:17

投稿

miyabi-sun
miyabi-sun

スコア21542

answer CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  ```JavaScript
6
6
  // この方法は楽だけど、正規表現やDateみたいなインスタンスが来ると困る
7
- JSON.stringify(JSON.parse(state));
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.stringify(JSON.parse(state))`で解決出来なければライブラリ使うべき。
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
- しかしpushが副作用のある破壊的メソッドだから、毎回シャローコピーする重い処理になったけ、これ関数型プログラミング的にはあるべき姿と思う
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 to_state = (state, it) => {
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(to_state, state));
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(4), 010: Array(2)}
76
+ // Object {001: Array(2), 010: Array(2)}
73
77
  ```

3

あれ、1と2は違うじゃん。というわけで1も回答

2017/08/25 01:17

投稿

miyabi-sun
miyabi-sun

スコア21542

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に修正

2017/08/24 15:21

投稿

miyabi-sun
miyabi-sun

スコア21542

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
- const data = Object.assign({}, state);
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

副作用があったので修正

2017/08/24 14:21

投稿

miyabi-sun
miyabi-sun

スコア21542

answer CHANGED
@@ -12,9 +12,8 @@
12
12
  こういった処理は関数的に解決するなら畳み込み!
13
13
  JSでは`[].reduce`というプロトタイプメソッドがあるのでそれを利用する。
14
14
 
15
- 速度はthink49さんが出したようなfor文を使うやり方にかないっこないんだけど、
16
15
  `to_state`の部分は関数として切り出せたから楽にテスト出来るね。
17
- ついでにリファクタリングて3行にしてたよ!(読みやなった言っていない)
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 (state[it.id] == null) state[it.id] = [];
39
+ if (data[it.id] == null) data[it.id] = [];
29
- state[it.id].push(it);
40
+ data[it.id].push(it);
30
- return state;
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 {100: Array(2), 001: Array(2)}
48
+ // Object {001: Array(4), 010: Array(2)}
35
49
  ```