UXPに備えてモダンなJSの書き方に慣れる(分割代入、スプレッド構文、シャローコピー、ディープコピー)

javascript

今回分割代入スプレッド構文に入ります。この辺りはアロー関数以上に見た目が???な構文が多いです。とはいえインターネット上のjs関係の記事では勿論jsのフレームワークのドキュメントでももはや当たり前のように扱われています。これはPhotoshop UXPも例外ではありません。例えばPhotoshop UXPの以下の構文は見たことがあると思います。

constとrequireはわかるけどappを囲む{}は一体何だ!?という疑問を持つと思います。これこそが分割代入です。これは以下と同様のコードです。

それでもまだしっくりこないとは思います。勿論こういった書き方は個人で開発する場合はする必要もあるわけではないですがもはや当たり前のように見かける書き方なので今後最新のjsの書き方に従った情報を手に入れる場合は読むだけでも慣れる必要があります。

分割代入 スプレッド構文

Destructing assignmentとも言われる分割代入構文はオブジェクトから値を取り出す、コピーするといった一連の流れを簡素に書くことが可能です。まずはオブジェクトからプロパティを取り出します。

これが冒頭のphotoshopモジュールからappプロパティを取っていたやり方です。{}で囲むことによりオブジェクトのプロパティを取り出しつつプロパティ名をそのまま変数名として使用できるのです。プロパティをまとめて取り出すことも可能です。

一部プロパティを取り出し後に残りのオブジェクトを新しいオブジェクトとしてコピーすることも可能です。

ちなみにこの「…」というのは立派な構文の一部なので注意してください。コメントとかそういった類のものではありません。その他でもかなり使用します。ちなみにプロパティを一切分割しなかった場合はオブジェクトのシャローコピーとなります。

コピー後のオブジェクトとコピー前のオブジェクトを等価性比較したところ中身は同じなのにfalseが返ってきました。jsにおいてオブジェクトをそのまま別の変数に代入すると参照渡しとなるだけでオブジェクトの複製それ自体ができるわけではないのは少し詳しい方ならご存知だと思います。

このようにただ単に代入しただけだと参照渡し、つまり変数名が異なるだけでobj2もobjも全く同じオブジェクトを参照することになるのです。参照先が同じである以上片方のプロパティを変えてももう片方も変わってしまいます。シャローコピーはこれを参照渡しでは無く実際にコピーするために見た目は同じでも中身の異なるオブジェクトを実際に複製するのです。

しかしこのシャローコピー、英語だとshallow copy(浅い 複製)と言われていますが浅いとはどういうことでしょうか?以下のオブジェクトのようにオブジェクトが入れ子になっている場合はどうでしょうか?

何と入れ子になったオブジェクトの親のオブジェクトはコピーされていますが子の関係のオブジェクトroomOneは同じオブジェクトを参照しています。

これこそがシャロー(浅い)コピーと呼ばれる所以でしょう。オブジェクトの浅い部分のみコピーしてネストされたオブジェクトは参照渡しにしかなっていないのです。深い階層までコピーできない、オブジェクトの参照渡しですら初心者殺しの要素であるのにシャローコピーというまた複雑な罠が仕掛けられているのがjsです。これはReactを使用する場合などにオブジェクト同士の比較がしょっちゅう行われるので重要な要素になります。ちなみにdeep copyに関してはJSON.parseで一度文字列に変換してからJSONに変換するという無理矢理な方法が検索するとよく引っかかりますが。

一見すると成功しているように見えますがundefinedの値、もしくはメソッドがある場合はどうでしょうか?

メソッドとundefinedを所有していたプロパティが消えました。やはり副作用はあるみたいです。このディープコピーを手っ取り早くやるにはlodashというライブラリで行うのが手っ取り早そうです。Lodash

簡単にディープコピーができました。ちなみにこのシャローコピーを使用してあるオブジェクトをベースにして新しいオブジェクトの作成も簡単にできます。

ちなみに分割代入のプロパティに対して新しい変数名を宣言することも可能。

関数の引数に対してもオブジェクトの分割代入は有効です。事前に関数の引数に使用するプロパティ名を変数として使用することでプロパティ名の頭にオブジェクト名をつける手間が省けるだけでなく事前に使用するプロパティを明示することが可能です。

ここまでオブジェクトの分割代入を解説しましたが次は配列の分割代入の解説に入ります。やり方はオブジェクトとほぼ同じ。

配列内の値をまとめて新しい変数に代入できるので簡素にコードが書けます。

この配列の分割代入ですがarray.pushメソッド、array.concatメソッドの代わりにもなります。

配列のコピーも勿論シャローコピーとしての役割も持っています。

ちなみに配列とオブジェクトで{}なのか[]か異なるので要注意。間違えやすいですが間違えると動きません。

参考記事 JavaScriptにおけるシャローコピーとディープコピーについて

Beer 寄付してサイトを応援する。