こんにちは、開発ブログ運営担当のsです。
現在担当している案件で、バグを修正するときに便利な関数があったので、メモとして残します。
前提
画面を上下で2分割し、2つの画像を表示して、それぞれの画像上に直線や領域を計測・描画する機能があります。
内部的には、 それぞれの計測結果を配列で保持しており、javascriptを使って画面に表示しています。
やりたかったこと
特定のパターンで片方の画像の計測結果が、もう片方の画像にも反映されてしまうバグが見つかりました。
デバッグで原因を探したところ、javascriptで配列を「=」でコピーした後に値を変更している箇所があり、
その結果、コピー元の配列の中身まで書き換わっていたことが原因でした。※
※javascript の「=」はオブジェクト型では参照渡しで代入されるため、以下のようにコピー元の配列まで変わってしまいます。
var array1 = [1, 2, 3]; // 配列「array1」の宣言と初期値の代入
var array2 = array1; // 配列「array2」を宣言して、配列「array1」を代入
array2[2] = 4; // 配列「array2」の3番目に「4」を代入
console.log(array2); // 配列「array2」の中身を出力する([1, 2, 4]と出力される。)
console.log(array1); // 配列「array1」の中身を出力する([1, 2, 3]ではなく、こちらも[1, 2, 4]と出力される。)
そのため「コピー元の配列に影響を与えず、コピー先の配列のみ変更したい」というのがやりたいことになります。
解決した方法
jQueryのextendメソッドを利用して、空配列に対してマージするように修正しました。
var array1 = [1, 2, 3];
var array2 = $.extend([ ], array1); // jQuery.extend( )を用いて、配列「array1」を「array2」にコピーする
array2[2] = 4;
console.log(array2); // 配列「array2」の中身を出力する([1, 2, 4]と出力される。)
console.log(array1); // 配列「array1」の中身を出力する([1, 2, 3]と出力される。)
この方法だと、コピー元の配列はそのままに、コピー先の配列のみ変更することが出来ました。
解説
jQuery.extend( )のメソッドは、元々オブジェクトの拡張やマージで用いられることが多いようですが、
今回は変則的にarray1の配列を空配列にマージさせることにより、array2の配列に対してarray1の配列の値渡しを実現しています。
jQuery.extend( ) の使い方 : $.extend([deep copy する場合は true], <コピー先>, <コピー元>)
引数は配列に限らず、Object({id:001, name:suzuki} など)でも使えます。
また、第1引数を true とすることで、中身を再帰的にマージすることも可能です。
(今回の場合、2行目を「var array2 = $.extend(true, [ ], array1); 」としても同様の結果となります。)
まとめ
普段、ちょっとした javascript を記述する分にはあまり意識しなくても良い部分ですが、
データの加工などで javascript で配列を扱う場合は「値渡し」と「参照渡し」を考えないとバグにつながってしまいます。
そのような場合に、コピー用の関数を自作するのもいいですが、jQuery を使うと記述するコードが少なくて済むと思います。