Quantcast
Channel: 配列タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 757

知らないとはまってしまうJavaScriptの配列コピー

$
0
0

概要

JavaScriptで配列コピーをする際、
「=(イコール)」によるコピーでは意図した動作にならない場合があります。
意外にはまりやすい落とし穴だと思ったので、
初心者にもわかりやすいよう、図も載せておきました。

配列コピーによる動き

まずは、動きを確認しましょう。

変数aの配列を宣言し、変数bにコピーします。

test.js
vara=['','','','',''];varb=a;

その後、変数b[0]の内容を書き換えます。

test.js
b[0]='';

この時、書き換えたいのは変数bの値ですが実際は

test.js
console.log('変数a: '+a);// ['か','い','う','え','お']console.log('変数b: '+b);// ['か','い','う','え','お']

と、変数aの値も書き換わってしまいます。
書き換えたのは変数bだったのに、なぜ変数aも一緒に書き換わってしまったのでしょうか。

コピー元の値が書き換わる理由

では、なぜ変数bの値を書き換えたにも関わらず、変数aの値も書き換わってしまったのか
図を交えて説明していきます。

まず、この変数aに格納されている値は、配列の情報ではなく、
配列aのインスタンスを参照するアドレスが格納されています。

その為、変数bに変数aをコピーした際、
配列ではなくアドレスの情報が渡されているのです。

実際に図にすると、以下の状態です。
配列コピー.jpg

次に、変数b[0]に「か」という文字を代入しましたが、
この時、変数b[0]は変数bの値を書き換えるのではなく、
配列の値を保持したメモリを直接書き換えることになります。

配列値変更.jpg

つまり、このb=aという式では、配列は複製されず
同じアドレス先を共有しているだけなのです。

この動作を理解していないと、
まるで両方の変数で値が書き換わったように感じてしまうのです。

配列をコピー(複製)する方法

では、実際に配列を複製するためにはどうすればいいか、いくつか例を挙げておきます。

for文によるコピー

for文を使って、配列要素文のループにより値を代入します。
この時、変数bは空の配列で宣言します。

test.js
vara=['','','','',''];varb=[];for(vari=0;i<a.length;i++){b[i]=a[i];}b[0]='';console.log('変数a: '+a);// ['あ','い','う','え','お']console.log('変数b: '+b);// ['か','い','う','え','お']

Array.concat()によるコピー

Arrayオブジェクトのconcatメソッドは指定された配列を連結して値を返すメソッドですが
引数を指定しない場合は、元の配列のコピーを返します。

test.js
vara=['','','','',''];varb=a.concat();b[0]='';console.log('変数a: '+a);// ['あ','い','う','え','お']console.log('変数b: '+b);// ['か','い','う','え','お']

Array.slice()によるコピー

Arrayオブジェクトのsliceオブジェクトは配列の一部を取り出して値を返すメソッドですが、
開始を指定し、終了を省略すると元の配列のコピーを返します。

test.js
vara=['','','','',''];varb=a.slice(0);b[0]='';console.log('変数a: '+a);// ['あ','い','う','え','お']console.log('変数b: '+b);// ['か','い','う','え','お']

まとめ

「=(イコール)」を使って変数の値をコピーする際には
その変数がなんの値を保持しているのか注意しましょう。


Viewing all articles
Browse latest Browse all 757

Trending Articles