WEBVTT

1
00:00:00.000 --> 00:00:00.857
こんにちは。

2
00:00:00.857 --> 00:00:05.287
今回はジャバスクリプトのストラクチャードクローンを紹介します。

3
00:00:05.287 --> 00:00:10.717
入れ子になったデータを、元とは独立した形で深くコピーするグローバル関数です。

4
00:00:10.717 --> 00:00:15.146
設定画面で入力を変更しても、保存するまでは元の設定を残したい。

5
00:00:15.146 --> 00:00:19.576
そんな場面では、内側まで独立した編集用データが必要になります。

6
00:00:19.576 --> 00:00:24.291
単に別の変数へ代入しただけでは、同じデータを指し続けてしまいます。

7
00:00:24.291 --> 00:00:29.078
この動画では、浅いコピーとの違い、基本の使い方、循環参照の扱い、コピーできない値、

8
00:00:29.078 --> 00:00:33.864
そして転送オプションまで、実行結果と一緒に学びます。

9
00:00:33.864 --> 00:00:39.580
身近なコピー手段との住み分けを理解すると、場面ごとに迷わず選べるようになります。

10
00:00:39.580 --> 00:00:42.844
まず、浅いコピーとの違いを確認します。

11
00:00:42.844 --> 00:00:49.199
オブジェクトを別の変数へ代入しても、それは同じデータを指しているだけです。

12
00:00:49.199 --> 00:00:57.443
スプレッド構文で外側だけをコピーしても、内側のオブジェクトは元のものと共有されたままになります。

13
00:00:57.443 --> 00:01:03.799
そのため、コピー側の内側を変更すると、元のデータまで変わってしまうのです。

14
00:01:03.799 --> 00:01:12.215
一方、ストラクチャードクローンで作った深いコピーでは、内側のオブジェクトも別物として複製されます。

15
00:01:12.215 --> 00:01:16.337
コピー側をいくら変更しても、元には影響しません。

16
00:01:16.337 --> 00:01:20.803
編集用データを作るときに必要なのは、この独立性です。

17
00:01:20.803 --> 00:01:29.048
この共有の仕組みは参照と呼ばれる考え方で、ジャバスクリプトを学ぶうえでの大切な土台でもあります。

18
00:01:29.048 --> 00:01:31.012
呼び出し方を確認します。

19
00:01:31.012 --> 00:01:36.576
第一引数にコピーしたい値を渡し、第二引数のオプションは省略できます。

20
00:01:36.576 --> 00:01:43.777
戻り値はコピーされた値で、オブジェクトを渡した場合は、元とは別のオブジェクトになります。

21
00:01:43.777 --> 00:01:47.214
注意したいのは、処理が同期的である点です。

22
00:01:47.214 --> 00:01:51.633
戻り値はプロミスではなく、その場でコピーが完成します。

23
00:01:51.633 --> 00:01:58.343
大量のデータを頻繁にコピーすると、その間、呼び出し側の処理が待たされてしまいます。

24
00:01:58.343 --> 00:02:05.053
そのため、コピーは編集開始時など、必要なタイミングと範囲に絞って使うのが基本です。

25
00:02:05.053 --> 00:02:11.436
対応しているかどうかは、関数として存在するかを実行前に確かめることもできます。

26
00:02:11.436 --> 00:02:13.697
記事の中心となる例を見ます。

27
00:02:13.697 --> 00:02:21.936
ユーザー名と通知設定を持つプロフィール、タグの配列、そして更新日時を持つ設定オブジェクトを用意します。

28
00:02:21.936 --> 00:02:27.266
これをストラクチャードクローンでコピーし、編集用データを作ります。

29
00:02:27.266 --> 00:02:33.404
そのうえで、コピー側だけ、通知をオフにし、タグを追加し、日時を一日進めます。

30
00:02:33.404 --> 00:02:37.766
ポイントは、変更がすべてコピー側に閉じていることです。

31
00:02:37.766 --> 00:02:45.358
元の設定は手つかずで残るため、ユーザーがキャンセルすれば、編集用データを捨てるだけで済みます。

32
00:02:45.358 --> 00:02:49.881
保存が決まったときだけ、編集結果を反映すればよいのです。

33
00:02:49.881 --> 00:02:55.696
この形は、フォームの編集画面で特によく使われる、実務に近いパターンです。

34
00:02:55.696 --> 00:02:57.252
実行結果を読みます。

35
00:02:57.252 --> 00:03:02.544
元の通知はトゥルーのまま、編集用の通知だけがフォルスになっています。

36
00:03:02.544 --> 00:03:09.392
タグも、元はジャバスクリプトだけですが、編集用にはノード・ジェイエスが追加されています。

37
00:03:09.392 --> 00:03:13.594
日時も、元は九月一日、編集用は九月二日と分かれました。

38
00:03:13.594 --> 00:03:17.641
さらに大切なのは、日時が文字列に化けていない点です。

39
00:03:17.641 --> 00:03:22.466
コピー後もデートとして扱え、日時のメソッドをそのまま使えます。

40
00:03:22.466 --> 00:03:26.824
内側のプロフィールが元と別物であることも確認できました。

41
00:03:26.824 --> 00:03:33.672
この出力はノード・ジェイエスの実機でも確認済みで、記事の期待出力と完全に一致しています。

42
00:03:33.672 --> 00:03:40.364
ユーティーシーで日時をそろえているため、この結果は実行環境の地域設定に左右されません。

43
00:03:40.364 --> 00:03:43.141
少し特殊な例として、循環参照を見ます。

44
00:03:43.141 --> 00:03:47.965
オブジェクトが自分自身を参照しているデータを、循環参照と呼びます。

45
00:03:47.965 --> 00:03:52.058
文字列化によるコピーでは、この形はエラーになりがちです。

46
00:03:52.058 --> 00:03:57.029
しかしストラクチャードクローンは、循環参照をそのままコピーできます。

47
00:03:57.029 --> 00:04:02.583
コピーは元とは別物であり、コピー側の自己参照は、コピー自身を正しく指します。

48
00:04:02.583 --> 00:04:04.922
元を指し続けることもありません。

49
00:04:04.922 --> 00:04:09.892
結果は順にトゥルー、トゥルー、フォルスとなり、実機でも確認済みです。

50
00:04:09.892 --> 00:04:15.009
循環をほどく処理を自分で書く必要がないのは、この関数の大きな強みです。

51
00:04:15.009 --> 00:04:20.856
同じオブジェクトへの参照が複数ある場合も、その関係はコピー側で正しく保たれます。

52
00:04:20.856 --> 00:04:23.381
コピーできる値の範囲を確認します。

53
00:04:23.381 --> 00:04:28.281
通常のオブジェクトや配列だけでなく、日時を表すデート、キーと値の組を保つマップ、

54
00:04:28.281 --> 00:04:33.182
重複のない集合であるセット、正規表現なども対象です。

55
00:04:33.182 --> 00:04:37.488
数値や文字列のような基本的な値は、そのままコピーされます。

56
00:04:37.488 --> 00:04:42.612
文字列化を経由する昔ながらの方法では、日時が文字列になったり、マップやセットが壊れたりしましたが、

57
00:04:42.612 --> 00:04:47.735
この関数なら型を保ったまま複製できます。

58
00:04:47.735 --> 00:04:55.012
ただし、ブラウザー専用のオブジェクトまで、ノード・ジェイエスで同じように扱えるわけではありません。

59
00:04:55.012 --> 00:04:59.021
環境をまたぐ場合は、共通して使える値に絞ってください。

60
00:04:59.021 --> 00:05:04.516
対応範囲の広さが、単純な文字列化によるコピーとの大きな違いになっています。

61
00:05:04.516 --> 00:05:06.070
失敗例を確認します。

62
00:05:06.070 --> 00:05:12.751
設定値と一緒に、保存処理のような関数を持つオブジェクトを渡すと、コピーは成功しません。

63
00:05:12.751 --> 00:05:21.918
関数だけを無視して残りをコピーするのではなく、呼び出し全体が失敗し、データクローンエラーという名前の例外が発生します。

64
00:05:21.918 --> 00:05:27.357
例外は同期的に発生するため、トライ・キャッチで捕まえることができます。

65
00:05:27.357 --> 00:05:36.835
実務では、テーマのようなデータと、保存処理のような振る舞いを分け、データ側だけをコピーする設計にすると扱いやすくなります。

66
00:05:36.835 --> 00:05:42.428
想定外の例外まで握りつぶさず、名前を確認してから処理する習慣も大切です。

67
00:05:42.428 --> 00:05:46.002
シンボルを含めた場合も、同様に例外になります。

68
00:05:46.002 --> 00:05:48.488
コピー前に中身を見直しましょう。

69
00:05:48.488 --> 00:05:52.140
もう一つの注意点は、振る舞いまでは複製されないことです。

70
00:05:52.140 --> 00:05:58.531
独自に作ったクラスのインスタンスを渡しても、メソッドを持った同じ種類のインスタンスにはなりません。

71
00:05:58.531 --> 00:06:01.661
プロトタイプやプライベートな要素、プロパティの読み取り専用といった細かな設定も、

72
00:06:01.661 --> 00:06:04.791
保持されません。

73
00:06:04.791 --> 00:06:08.051
正規表現の検索位置も、コピーでは引き継がれません。

74
00:06:08.051 --> 00:06:09.617
ドムノードも対象外です。

75
00:06:09.617 --> 00:06:13.399
つまり、この関数が複製するのは、あくまでデータの構造です。

76
00:06:13.399 --> 00:06:19.268
コピーしたいものがデータなのか、振る舞いを持つインスタンスなのかを、先に判断してください。

77
00:06:19.268 --> 00:06:24.876
読み取り専用だった項目が、コピー側では書き換え可能になる点も、見落としやすい変化です。

78
00:06:24.876 --> 00:06:27.506
最後に、転送オプションを押さえます。

79
00:06:27.506 --> 00:06:34.375
第二引数にトランスファーを指定すると、指定した転送可能な資源が、コピーではなく移動になります。

80
00:06:34.375 --> 00:06:38.686
バイト配列のバッファーを転送する例では、転送先では中身を読めますが、元のバッファーは切り離され、

81
00:06:38.686 --> 00:06:42.996
長さがゼロになります。

82
00:06:42.996 --> 00:06:48.696
指定するのは配列そのものではなく、そのバッファーである点にも注意してください。

83
00:06:48.696 --> 00:06:54.833
編集前のデータを残したい今回のような用途では、このオプションは省略するのが正解です。

84
00:06:54.833 --> 00:06:59.071
転送は、元を手放してよい場面専用の仕組みと覚えてください。

85
00:06:59.071 --> 00:07:04.624
同じバッファーを別のビューが参照している場合、そのビューにも影響が及びます。

86
00:07:04.624 --> 00:07:05.605
まとめです。

87
00:07:05.605 --> 00:07:10.184
ストラクチャードクローンは、入れ子のデータを独立して深くコピーする関数で、

88
00:07:10.184 --> 00:07:14.762
循環参照や日時、マップなども扱えます。

89
00:07:14.762 --> 00:07:16.725
導入時の判断は三つです。

90
00:07:16.725 --> 00:07:23.756
まず、コピー対象を通常のデータに絞り、関数や独自クラスが混ざっていないか確認すること。

91
00:07:23.756 --> 00:07:30.624
次に、編集開始など必要なタイミングに絞って呼び出し、毎回全体をコピーし続けないこと。

92
00:07:30.624 --> 00:07:36.348
そして、履歴機能に使う場合は、保存件数や対象範囲を先に決めることです。

93
00:07:36.348 --> 00:07:44.851
練習として、小さな設定オブジェクトをコピーし、内側を変更しても元が変わらないことを確かめてみてください。

94
00:07:44.851 --> 00:07:46.323
お疲れさまでした。

95
00:07:46.323 --> 00:07:52.700
小さな例で確かめる習慣が、共有や例外による思わぬ不具合を未然に防いでくれます。
