JavaScriptで配列をコピーする方法まとめ（多次元配列含む）

# 最初に
JavaScriptのオブジェクトをコピーする方法については、[こちらの記事](https://qiita.com/chimeiwang/items/60568677f8c6c130f91c)をクリックしてください。
本記事では配列のコピー方法を紹介しています。

JavaScriptでは、大別してプリミティブ型（データ型）とノンプリミティブ型（構造型）の二つがあります。string・number・booleanなどはプリミティブ型、オブジェクト・配列・関数などはノンプリミティブ型と分けています。（[MDN参照](https://developer.mozilla.org/ja/docs/Web/JavaScript/Data_structures)）

プリミティブ型データに対して、簡単に`x = y`をすると値渡しのコピーができますが、ノンプリミティブ型データにはこのようにコピーすると参照渡しのコピー（データの置き場所）になります。

コード例：

```js
// プリミティブ型
let name = "Kimmy"
let nameCopy = name

nameCopy = "Qiita"

// 値渡しのコピーなのでanotherNameの値は変更されていません
console.log(name)  // Kimmy
console.log(nameCopy)  //Qiita

// ノンプリミティブ型
let animals = ['lion', 'owl', 'dog'];
let animalsCopy = animals

animalsCopy[0] = "cat"

// 参照渡しのコピーなので、一方を変更すると両方に変更が反映されます
console.log(animals)  // ["cat", "owl", "dog"]
console.log(animalsCopy)  // ["cat", "owl", "dog"]
```

# コピー方法について
コピーには浅いコピーと深いコピー２つがあります。
- **浅いコピー**：１段階のデータのみ値渡しのコピーになり、２段階以上のデータには参照渡しのコピーになります。
- **深いコピー**：多階層のデータでも、オブジェクトは最も深いところまですべての値をコピーします。
なので、データの深さを考える必要があります。

# 浅いコピー（Shallow Copy）

以下`animal`配列のような階層を持っていないデータを例としてコピーを行います。

## `concat()`
```js
let animal = ['lion', 'owl', 'dog'];
let animalCopy = [].concat(animal);

animalCopy.push('cat');

console.log(animal); // ["lion", "owl", "dog"]
console.log(animalCopy); // ["lion", "owl", "dog", "cat"]
```

## `slice()`

```js
let animal = ['lion', 'owl', 'dog'];
let animalCopy = animal.slice();

animalCopy.push('cat');

console.log(animal); // ["lion", "owl", "dog"]
console.log(animalCopy); // ["lion", "owl", "dog", "cat"]
```

## `Object.assign()`
配列はオブジェクトから派生した構造的な型なので、`Object.assign()`も使えます。

```js
let animal = ['lion', 'owl', 'dog'];
let animalCopy = Object.assign([], animal);

animalCopy.push('cat');

console.log(animal); // ["lion", "owl", "dog"]
console.log(animalCopy); // ["lion", "owl", "dog", "cat"]
```

## `Array.from()`
`Array.from()`はES2015で追加されたメソッドです。

```js
let animal = ['lion', 'owl', 'dog'];
let animalCopy = Array.from(animal);

animalCopy.push('cat');

console.log(animal); // ["lion", "owl", "dog"]
console.log(animalCopy); // ["lion", "owl", "dog", "cat"]
```

## スプレッド構文
ES2015で追加されたスプレッド構文を利用した浅いコピーができます。

```js
let animal = ['lion', 'owl', 'dog'];
let animalCopy = [...animal];

animalCopy.push('cat');

console.log(animal); // ["lion", "owl", "dog"]
console.log(animalCopy); // ["lion", "owl", "dog", "cat"]
```


# 深いコピー（Deep Copy）
[Lodash](https://lodash.com/)や[Ramda](https://ramdajs.com/)などのJavaScriptライブラリーを使って、深いコピーもできますが、今回はライブラリーなしの方法を紹介します。

```js
function cloneArray(array) {
  let clone = [];
  array.forEach((item) =>
    Array.isArray(item) ? clone.push(cloneArray(item)) : clone.push(item)
  );
  return clone;
}
```

```js
let animal = [["dog", "cat"], ["lion", "tiger"], "owl"];

let animalClone = cloneArray(animal); // 深いコピー
let faultyClone = [...animal] // 浅いコピーの一つ

animal[0][0] = "dinosaur"; // "dog"から"dinosaur"に変更される

console.log(animal); // ["dinosaur", "cat"], ["lion", "tiger"], "owl"]

// 浅いコピーはdinosaurに変更される
console.log(faultyClone); // ["dinosaur", "cat"], ["lion", "tiger"], "owl"]

// 深いコピーは変更なし
console.log(animalClone); // ["dog", "cat"], ["lion", "tiger"], "owl"]
```

#最後に
ここまでお読みいただきありがとうございました。
他の方法がございましたら、ぜひコメント欄にシェアしてください。
また、文法ミスや誤字がありましたら、編集リクエストでご意見をいただければと思います。