😎

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

2021/04/17に公開
3

破壊的メソッドの何がまずいのか?

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

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

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

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

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

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

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()

Array.prototype.push()

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

破壊

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

非破壊

// スプレッド構文
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()

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

破壊

const numbers = [1, 2, 3, 4, 5];
numbers.unshift(0);
console.log(numbers); // [0, 1, 2, 3, 4, 5]

非破壊

// スプレッド構文
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()

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

破壊

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

非破壊

// スプレッド構文
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()

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

破壊

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

非破壊

// スプレッド構文
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()

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

破壊

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

非破壊

// スプレッド構文
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()

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

破壊

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

非破壊

// スプレッド構文
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()

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

破壊

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

非破壊

// スプレッド構文
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()

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

破壊

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

非破壊

// スプレッド構文
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/

Discussion