【JavaScript】破壊的メソッドの非破壊的な書き方

# 破壊的メソッドの何がまずいのか？
破壊的メソッドを使うとコードの読み手に混乱を与えてしまう可能性があります。

**破壊的メソッドを使った例**

```js
const numbers = [1, 2, 3, 4, 5];

// とても長い処理
numbers.push(6); <- 読み飛ばされてしまう可能性が高い
// とても長い処理

console.log(numbers); <- 読み手は[1, 2, 3, 4, 5]を期待している
// 実際は[1, 2, 3, 4, 5, 6]; 
```

**非破壊的メソッドを使った例**

```js
const numbers = [1, 2, 3, 4, 5];

// とても長い処理
const newNumbers = numbers.concat(6);
// とても長い処理

console.log(numbers); // [1, 2, 3, 4, 5] 読み手の期待通りのまま
console.log(newNumbers); // [1, 2, 3, 4, 5, 6]
```



# 結論
スプレッド構文を使えばOK！
以下、具体的な書き方と別の書き方をまとめます。

## 目次

> [push()](#push)
[unshift()](#unshift)
[pop()](#pop)
[shift()](#shift)
[sort()](#sort)
[reverse()](#reverse)
[copyWithin()](#copyWithin)

# push()
[Array.prototype.push()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/push)

> push() メソッドは、配列の末尾に 1 つ以上の要素を追加することができます。また戻り値として新しい配列の要素数を返します。

## 破壊

```js
const numbers = [1, 2, 3, 4, 5];
numbers.push(6);
console.log(numbers); // [1, 2, 3, 4, 5, 6]
```
## 非破壊

```js
// スプレッド構文
const numbers = [1, 2, 3, 4, 5];
const newNumbers = [...numbers, 6];
console.log(numbers); // [1, 2, 3, 4, 5]
console.log(newNumbers); // [1, 2, 3, 4, 5, 6]

// concat()
const numbers = [1, 2, 3, 4, 5];
const newNumbers = numbers.concat(6);
console.log(numbers); // [1, 2, 3, 4, 5]
console.log(newNumbers); // [1, 2, 3, 4, 5, 6]
```

# unshift()
[Array.prototype.unshift()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/unshift)

> unshift() メソッドは、配列の最初に 1 つ以上の要素を追加し、新しい配列の長さを返します。

## 破壊

```js
const numbers = [1, 2, 3, 4, 5];
numbers.unshift(0);
console.log(numbers); // [0, 1, 2, 3, 4, 5]
```
## 非破壊

```js
// スプレッド構文
const numbers = [1, 2, 3, 4, 5];
const newNumbers = [0, ...numbers];
console.log(numbers); // [1, 2, 3, 4, 5]
console.log(newNumbers); // [0, 1, 2, 3, 4, 5]

// concat()
const numbers = [1, 2, 3, 4, 5];
const newNumbers = [0].concat(numbers);
console.log(numbers); // [1, 2, 3, 4, 5]
console.log(newNumbers); // [0, 1, 2, 3, 4, 5]
```
# pop()
[Array.prototype.pop()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/pop)

> pop() メソッドは、配列から最後の要素を取り除き、その要素を返します。このメソッドは配列の長さを変化させます。

## 破壊

```js
const numbers = [1, 2, 3, 4, 5];
numbers.pop();
console.log(numbers); // [1, 2, 3, 4]
```
## 非破壊

```js
// スプレッド構文
const numbers = [1, 2, 3, 4, 5];
const newNumbers = [...numbers];
newNumbers.pop()
console.log(numbers); // [1, 2, 3, 4, 5]
console.log(newNumbers); // [1, 2, 3, 4]

// slice()
const numbers = [1, 2, 3, 4, 5];
const newNumbers = numbers.slice(0, 4);
console.log(numbers); // [1, 2, 3, 4, 5]
console.log(newNumbers); // [1, 2, 3, 4]
```
# shift()
[Array.prototype.shift()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/shift)

> shift() メソッドは、配列から最初の要素を取り除き、その要素を返します。このメソッドは配列の長さを変えます。

## 破壊

```js
const numbers = [1, 2, 3, 4, 5];
numbers.shift();
console.log(numbers); // [2, 3, 4, 5]
```
## 非破壊

```js
// スプレッド構文
const numbers = [1, 2, 3, 4, 5];
const newNumbers = [...numbers];
newNumbers.shift();
console.log(numbers); // [1, 2, 3, 4, 5]
console.log(newNumbers); // [2, 3, 4, 5]


// slice()
const numbers = [1, 2, 3, 4, 5];
const newNumbers = numbers.slice(1, 5);
console.log(numbers); // [1, 2, 3, 4, 5]
console.log(newNumbers); // [2, 3, 4, 5]
```

# sort()
[Array.prototype.sort()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)

> sort() メソッドは、配列の要素を in place でソートします。既定のソート順は昇順で、要素を文字列に変換してから、UTF-16 コード単位の値の並びとして比較します。

## 破壊

```js
const numbers = [5, 1, 4, 2, 3];
numbers.sort();
console.log(numbers); // [1, 2, 3, 4, 5]
```

## 非破壊

```js
// スプレッド構文
const numbers = [5, 1, 4, 2, 3];
newNumbers = [...numbers].sort()
console.log(numbers); // [5, 1, 4, 2, 3]
console.log(newNumbers); // [1, 2, 3, 4, 5]
```

# reverse()
[Array.prototype.reverse()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse)

> reverse() メソッドは、配列の要素を In-place アルゴリズムで反転させます。最初の要素が最後の要素に、最後の要素が最初の要素になります。

## 破壊

```js
const numbers = [1, 2, 3, 4, 5];
numbers.reverse();
console.log(numbers); // [5, 4, 3, 2, 1]
```

## 非破壊

```js
// スプレッド構文
const numbers = [1, 2, 3, 4, 5];
newNumbers = [...numbers].reverse()
console.log(numbers); // [1, 2, 3, 4, 5]
console.log(newNumbers); // [5, 4, 3, 2, 1]
```

# fill()
[Array.prototype.fill()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/fill)

> fill() メソッドは、開始インデックス（デフォルトは 0）から終了インデックス（デフォルトは array.length）までのすべての要素を、静的な値に変更した配列を返します。

## 破壊

```js
const numbers = [1, 2, 3, 4, 5];
numbers.fill(7);
console.log(numbers); // [7, 7, 7, 7, 7]
```

## 非破壊

```js
// スプレッド構文
const numbers = [1, 2, 3, 4, 5];
newNumbers = [...numbers].fill(7)
console.log(numbers); // [1, 2, 3, 4, 5]
console.log(newNumbers); // [7, 7, 7, 7, 7]
```

# copyWithin()
[Array.prototype.copyWithin()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/copyWithin)

> copyWithin() メソッドは、サイズを変更せずに、配列の一部を同じ配列内の別の場所にシャローコピーして返します。

## 破壊

```js
const numbers = [1, 2, 3, 4, 5];
numbers.copyWithin(2, 3, 5);
console.log(numbers); // [ 1, 2, 4, 5, 5 ]
```

## 非破壊

```js
// スプレッド構文
const numbers = [1, 2, 3, 4, 5];
newNumbers = [...numbers].copyWithin(2, 3, 5);
console.log(numbers); // [1, 2, 3, 4, 5]
console.log(newNumbers); // [ 1, 2, 4, 5, 5 ]
```

# 参考
https://developer.mozilla.org/ja/