【納得!】配列のコピー・複製がうまくいかない原因と理由【JavaScript】

JavaScript

みなさんこんにちは、現役エンジニアのサメハックです

アパレル企業でトップ販売員を経て
未経験からWebエンジニアに転職し、
現在正社員として5年働いています!

JavaScriptの解説シリーズです。

今回は配列をコピー・複製する方法について学んでいきましょう!

駆け出しエンジニアや未経験の方、
また新入社員を指導する先輩社員にとっても
わかりやすいように解説していきます!

この記事を読むと・・・
  • 配列の作り方がわかる
  • 配列のコピー・複製が出来るようになる
配列をマスターしよう!

配列とは

複数のデータを入れておく箱です

例えば、Fishesという箱の中に
ナマズ, サケ, タイ
の3匹が入っているようなイメージです。

配列は複数のデータを入れておく箱だよ!

配列の作り方

■構文

配列名 = [データ0, データ1, データ2]

このように、ブラケット[]の中に
カンマ区切りでデータを列挙することで配列を作成できます。

先ほどの魚の例をコーディングしてみましょう。

const fishes = ["ナマズ", "サケ", "タイ"]

console.log(fishes)
// 【出力結果】["ナマズ", "サケ", "タイ"]
ちなみに、定数で宣言しているけど配列の中身は操作できるよ!

配列のコピー・複製がうまくいかない

間違った記述

一般的に要素をコピー・複製する際には

const 新しい配列 = 配列X;

というような記述になるかと思いますが、
配列に関してはこの記述方法は間違いです!

新しい配列 = 配列X; と記述した場合の挙動

さきほどの間違った記述方法ではどのような挙動になるのかを見てみましょう。

// 配列1の宣言
const array1 = [0, 1, 2, 3];

// 配列2の宣言
// ※間違った記述
const array2 = array1;

console.log(array2);
// 【出力結果】  [0, 1, 2, 3]

// 配列1に要素を追加
array1.push(999);

console.log(array1);
// 【出力結果】  [0, 1, 2, 3, 999]

/* 操作していないはずの配列2にも999が追加される */
console.log(array2);
// 【出力結果】  [0, 1, 2, 3, 999]

このように新しい配列 = 古い配列; という記述をすると
古い配列を操作した際に、新しい配列にも変更が反映されてしまいます。

参照渡し

プログラムにはメモリというデータを仮置きする領域があるのですが、
同じメモリ領域を参照する動きを参照渡しといいます。

JavaScriptにおいてオブジェクト・配列をイコールでつなぐと、
データのコピー・複製ではなく、参照渡しという動きをします。

配列2 = 配列1;

上記は、配列1と配列2で同じデータ領域を参照しよう!という処理です。

この仕様によって、配列1に999を追加しただけなのに
配列2の中身にも999が追加されたように見えた、ということです。

メモリ領域と考えるとややこしいけど、
単純にデータをシェアしているだけだと考えてOKだよ!

値渡し

ちなみに、値そのものを渡すことを値渡しといいます。
JavaScriptにおいてはプリミティブ型は値渡しされます。

■ プリミティブ型

  • 文字列型
  • 数値型
  • 真偽値(Boolean)型
  • null型
  • undefined型
みんなのよく知るデータのコピー・複製はこの動きをしているよ!

配列を”値渡し”する2つの方法

slice関数

slice関数を引数なしで使うことで、配列の値渡しができます。

// 配列1の宣言
const array1 = [0, 1, 2, 3];

// slice関数を使って値渡しする
const array2 = array1.slice();

console.log(array2);
// 【出力結果】  [0, 1, 2, 3]

// 配列1に要素を追加
array1.push(999);

console.log(array1);
// 【出力結果】  [0, 1, 2, 3, 999]

/* 配列2には999が追加されない */
console.log(array2);
// 【出力結果】  [0, 1, 2, 3]
これで配列1と配列2は別物という扱いになるよ!

concat関数

もう一つのやりかたとして、concat関数を使う方法があります。

// 配列1の宣言
const array1 = [0, 1, 2, 3];

// concat関数を使って値渡しする
const array2 = array1.concat();

console.log(array2);
// 【出力結果】  [0, 1, 2, 3]

// 配列1に要素を追加
array1.push(999);

console.log(array1);
// 【出力結果】  [0, 1, 2, 3, 999]

/* 配列2には999が追加されない */
console.log(array2);
// 【出力結果】  [0, 1, 2, 3]
結果は同じなので好きな方を使ってみてね!

JSONを使う方法

基本的には上記のいずれかで出来ますが、
どうしてもうまく行かない場合はJSONを使ってください。

// 配列1の宣言
const array1 = [0, 1, 2, 3];

// JSONを使って値渡しする
const array2 = JSON.parse(JSON.stringify(array1));

console.log(array2);
// 【出力結果】  [0, 1, 2, 3]

// 配列1に要素を追加
array1.push(999);

console.log(array1);
// 【出力結果】  [0, 1, 2, 3, 999]

/* 配列2には999が追加されない */
console.log(array2);
// 【出力結果】  [0, 1, 2, 3]
うまく行かない場合に使ってみてね!

まとめ

  • 配列1 = 配列2; という記述では中身の複製はできない
  • ↑は参照渡しといい、配列1・2で同じメモリ領域を参照する≒中身が同じとなる
  • 配列を複製するには 配列.slice() または 配列.concat() を使う

満足いただけたら、1クリックなのでSNSフォローしてもらえると嬉しいです🦈

タイトルとURLをコピーしました